rewrote memory system entirely (hunk, cache, and zone are gone, memory pools replaced...
authorlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 16 Jan 2002 06:16:58 +0000 (06:16 +0000)
committerlordhavoc <lordhavoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 16 Jan 2002 06:16:58 +0000 (06:16 +0000)
models can be reloaded at any time (Mod_CheckLoaded, etc)
entire renderer can be restarted using r_restart command
batch triangle mesh rendering system (gl_backend.c)
most rendering code does not touch GL anymore
gl_textures now supports procedural textures, and fragment textures (small textures combined into larger images)
lightmaps can now be mipmapped (r_miplightmaps)
broke up r_part.c and r_decals.c into cl_particles.c, r_particles.c, cl_decals.c, and r_decals.c to improve renderer/client separation, but explosions are still renderer
moved CL_NextDemo from cl_main.c to cl_demo.c
cleaned up demo stop/disconnect code
removed render modules stuff from all cl_ files
renderer uses separate light array, and recalculates radius for lights based on color, and calculates subtract value to give it a soft edge at the radius perimeter
small surfaces do not use lightmaps (unfortunately they still look slightly different in dynamic lighting)
items can now bob according to cl_itembob* cvars
moved CL_SignonReply from cl_main.c to cl_parse.c
monster movement interpolation is now done clientside instead of serverside, Nehahra movie should look better now
cvars now have a .integer field containing the integer value of their string (nearly all .value accesses have been changed to .integer for speed reasons)
pmodel is now only available in Nehahra mode (pmodel was a bad hack)
r_farclip cvar removed, farclip now dynamically adjusts to level as you explore it
parsing of wad names out of HL maps is now in renderer code
changed isworldmodel stuff in model loading
cleaned up CL_ParseUpdate a bit (related to clientside monster interpolation)
renamed r_glowinglightning to cl_glowinglightning
moved FindNonSolidLocation to bmodel code
lightning beam models are now only looked up once
entity_t now contains an entity_persistent_t which holds data persistent from frame to frame (interpolation mainly), entity_render_t is wiped every frame
marked a lot more things as static
increased command buffer (script execution buffer) from 8k to 32k
COM_LoadMallocFile has been renamed to COM_LoadFile, and all other variants are gone
rounding on MSG_Read/Write stuff has been changed to fix negative rounding (C rounds toward zero, old code assumed it always rounded down)
improved cachepic (menu images) system to load from wad
statusbar now uses cachepic system
cachepics are cleared when renderer is restarted
fixed fog on transparent objects, should always look correct now
moved R_TimeRefresh_f from gl_rmisc.c to gl_rmain.c
moved R_NewMap from gl_rmisc.c to gl_rmain.c
deleted gl_rmisc.c
removed support for glfog
masked sky rendering is now done by first rendering the sky scene, clearing the depthbuffer, rendering invisible depth polys over it, then rendering the scene, this is for more flexibility
C-code based shader system (not scripted)
deleted hcompress.c
due to more thorough memory corruption detection, a (harmless with old zone system) buffer overflow bug in the client name command was fixed
untested (and quite possibly broken) quaternion math stuff added to mathlib.h
removed support for colormod entity effect (massive mess to support it everywhere)
improved QC PR_RunError reports
moved QC opcode execution loop into pr_execprogram.h, included multiple times
fairly major sbar cleanup
rearranged GL extension detection again
added EXT_texture_env_combine support

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@1343 d7cf8633-e32d-0410-b094-e92efae38249

103 files changed:
buildnumber.c
chase.c
cl_decals.c [new file with mode: 0644]
cl_demo.c
cl_light.c
cl_light.h
cl_main.c
cl_parse.c
cl_particles.c [new file with mode: 0644]
cl_tent.c
client.h
cmd.c
cmd.h
common.c
common.h
console.c
cvar.c
cvar.h
draw.h
fractalnoise.c
gl_backend.c [new file with mode: 0644]
gl_backend.h [new file with mode: 0644]
gl_draw.c
gl_models.c
gl_rmain.c
gl_rmisc.c [deleted file]
gl_rsurf.c
gl_screen.c
gl_textures.c
glquake.h
hcompress.c [deleted file]
host.c
host_cmd.c
image.c
image.h
in_svgalib.c
in_win.c
makefile
mathlib.c
mathlib.h
menu.c
model_alias.c
model_alias.h
model_brush.c
model_brush.h
model_shared.c
model_shared.h
model_sprite.c
model_sprite.h
modelgen.h
net_main.c
palette.c
palette.h
portals.c
pr_cmds.c
pr_edict.c
pr_exec.c
pr_execprogram.h [new file with mode: 0644]
progs.h
protocol.c
protocol.h
quakedef.h
quakeio.c
r_clip.c
r_crosshairs.c
r_decals.c
r_explosion.c
r_lerpanim.c
r_light.c
r_light.h
r_modules.c
r_part.c [deleted file]
r_particles.c [new file with mode: 0644]
r_sky.c [new file with mode: 0644]
r_sprites.c
r_textures.h
render.h
sbar.c
snd_dma.c
snd_mem.c
sound.h
spritegn.h
sv_light.c
sv_main.c
sv_phys.c
sv_user.c
sys_linux.c
sys_shared.c
sys_win.c
transform.c
transform.h
ui.c
vid_3dfxsvga.c
vid_glx.c
vid_shared.c
vid_wgl.c
view.c
wad.c
wad.h
world.c
world.h
zone.c
zone.h

index 8ec24a4..2d3037b 100644 (file)
@@ -1,4 +1,4 @@
 
 
-#define BUILDNUMBER 256
+#define BUILDNUMBER 604
 
 int buildnumber = BUILDNUMBER;
 
 int buildnumber = BUILDNUMBER;
diff --git a/chase.c b/chase.c
index f4ee5b9..1b6e78e 100644 (file)
--- a/chase.c
+++ b/chase.c
@@ -44,6 +44,11 @@ float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int con
 {
        trace_t trace;
 
 {
        trace_t trace;
 
+// FIXME: broken, fix it
+//     if (impact == NULL && normal == NULL && contents == 0)
+//             return SV_TestLine (cl.worldmodel->hulls, 0, start, end);
+
+       Mod_CheckLoaded(cl.worldmodel);
        memset (&trace, 0, sizeof(trace));
        VectorCopy (end, trace.endpos);
        trace.fraction = 1;
        memset (&trace, 0, sizeof(trace));
        VectorCopy (end, trace.endpos);
        trace.fraction = 1;
diff --git a/cl_decals.c b/cl_decals.c
new file mode 100644 (file)
index 0000000..0a071c5
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+#define MAX_DECALS 2048
+
+typedef struct decal_s
+{
+       entity_render_t *ent;
+       int tex;
+       model_t *model;
+       int surface;
+       float scale;
+       vec3_t org;
+       vec3_t dir;
+       float color[4];
+}
+decal_t;
+
+static decal_t *cl_decals;
+static int cl_currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
+
+static renderdecal_t *cl_renderdecals;
+
+static mempool_t *cl_decal_mempool;
+
+void CL_Decals_Clear(void)
+{
+       memset(cl_decals, 0, MAX_DECALS * sizeof(decal_t));
+       cl_currentdecal = 0;
+}
+
+void CL_Decals_Init(void)
+{
+       cl_decal_mempool = Mem_AllocPool("CL_Decals");
+       cl_decals = (decal_t *) Mem_Alloc(cl_decal_mempool, MAX_DECALS * sizeof(decal_t));
+       memset(cl_decals, 0, MAX_DECALS * sizeof(decal_t));
+       cl_currentdecal = 0;
+
+       // FIXME: r_refdef stuff should be allocated somewhere else?
+       r_refdef.decals = cl_renderdecals = Mem_Alloc(cl_decal_mempool, MAX_DECALS * sizeof(renderdecal_t));
+}
+
+
+// these are static globals only to avoid putting unnecessary things on the stack
+static vec3_t decalorg, decalbestorg;
+static float decalbestdist;
+static msurface_t *decalbestsurf;
+static entity_render_t *decalbestent, *decalent;
+static model_t *decalmodel;
+void CL_RecursiveDecalSurface (mnode_t *node)
+{
+       // these are static because only one occurance of them need exist at once, so avoid putting them on the stack
+       static float ndist, dist;
+       static msurface_t *surf, *endsurf;
+       static vec3_t impact;
+       static int ds, dt;
+
+loc0:
+       if (node->contents < 0)
+               return;
+
+       ndist = PlaneDiff(decalorg, node->plane);
+
+       if (ndist > 16)
+       {
+               node = node->children[0];
+               goto loc0;
+       }
+       if (ndist < -16)
+       {
+               node = node->children[1];
+               goto loc0;
+       }
+
+// mark the polygons
+       surf = decalmodel->surfaces + node->firstsurface;
+       endsurf = surf + node->numsurfaces;
+       for (;surf < endsurf;surf++)
+       {
+               if (!(surf->flags & SURF_LIGHTMAP))
+                       continue;
+
+               dist = PlaneDiff(decalorg, surf->plane);
+               if (surf->flags & SURF_PLANEBACK)
+                       dist = -dist;
+               if (dist < -1)
+                       continue;
+               if (dist >= decalbestdist)
+                       continue;
+
+               impact[0] = decalorg[0] - surf->plane->normal[0] * dist;
+               impact[1] = decalorg[1] - surf->plane->normal[1] * dist;
+               impact[2] = decalorg[2] - surf->plane->normal[2] * dist;
+
+               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
+               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
+
+               if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
+                       continue;
+
+               VectorCopy(decalorg, decalbestorg);
+               decalbestent = decalent;
+               decalbestsurf = surf;
+               decalbestdist = dist;
+       }
+
+       if (node->children[0]->contents >= 0)
+       {
+               if (node->children[1]->contents >= 0)
+               {
+                       CL_RecursiveDecalSurface (node->children[0]);
+                       node = node->children[1];
+                       goto loc0;
+               }
+               else
+               {
+                       node = node->children[0];
+                       goto loc0;
+               }
+       }
+       else if (node->children[1]->contents >= 0)
+       {
+               node = node->children[1];
+               goto loc0;
+       }
+}
+
+void CL_Decal(vec3_t origin, int tex, float scale, float red, float green, float blue, float alpha)
+{
+       int i;
+       decal_t *decal;
+
+       if (alpha < (1.0f / 255.0f))
+               return;
+
+       // find the best surface to place the decal on
+       decalbestent = NULL;
+       decalbestsurf = NULL;
+       decalbestdist = 16;
+
+       decalent = NULL;
+       decalmodel = cl.worldmodel;
+       Mod_CheckLoaded(decalmodel);
+       VectorCopy(origin, decalorg);
+       CL_RecursiveDecalSurface (decalmodel->nodes);
+
+       for (i = 1;i < MAX_EDICTS;i++)
+       {
+               decalent = &cl_entities[i].render;
+               decalmodel = decalent->model;
+               if (decalmodel && decalmodel->name[0])
+               {
+                       Mod_CheckLoaded(decalmodel);
+                       if (decalmodel->type == mod_brush)
+                       {
+                               softwaretransformforentity(decalent);
+                               softwareuntransform(origin, decalorg);
+                               CL_RecursiveDecalSurface (decalmodel->nodes);
+                       }
+               }
+       }
+
+       // abort if no suitable surface was found
+       if (decalbestsurf == NULL)
+               return;
+
+       // grab a decal from the array and advance to the next decal to replace, wrapping to replace an old decal if necessary
+       decal = &cl_decals[cl_currentdecal++];
+       if (cl_currentdecal >= MAX_DECALS)
+               cl_currentdecal = 0;
+       memset(decal, 0, sizeof(*decal));
+
+       decal->ent = decalbestent;
+       if (decal->ent)
+               decal->model = decal->ent->model;
+       else
+               decal->model = cl.worldmodel;
+
+       decal->tex = tex + 1; // our texture numbers are +1 to make 0 mean invisible
+       VectorNegate(decalbestsurf->plane->normal, decal->dir);
+       if (decalbestsurf->flags & SURF_PLANEBACK)
+               VectorNegate(decal->dir, decal->dir);
+       // 0.25 to push it off the surface a bit
+       decalbestdist -= 0.25f;
+       decal->org[0] = decalbestorg[0] + decal->dir[0] * decalbestdist;
+       decal->org[1] = decalbestorg[1] + decal->dir[1] * decalbestdist;
+       decal->org[2] = decalbestorg[2] + decal->dir[2] * decalbestdist;
+       decal->scale = scale * 0.5f;
+       // store the color
+       decal->color[0] = red;
+       decal->color[1] = green;
+       decal->color[2] = blue;
+       decal->color[3] = alpha;
+       // store the surface information
+       decal->surface = decalbestsurf - decal->model->surfaces;
+}
+
+void CL_UpdateDecals (void)
+{
+       int i;
+       decal_t *p;
+       renderdecal_t *r;
+
+       for (i = 0, p = cl_decals, r = r_refdef.decals;i < MAX_DECALS;i++, p++)
+       {
+               if (p->tex == 0)
+                       continue;
+
+               if (p->ent && p->ent->visframe == r_framecount && p->ent->model != p->model)
+               {
+                       p->tex = 0;
+                       continue;
+               }
+
+               r->ent = p->ent;
+               r->tex = p->tex - 1; // our texture numbers are +1 to make 0 mean invisible
+               r->surface = p->surface;
+               r->scale = p->scale;
+               VectorCopy(p->org, r->org);
+               VectorCopy(p->dir, r->dir);
+               VectorCopy4(p->color, r->color);
+               r++;
+       }
+       r_refdef.numdecals = r - r_refdef.decals;
+}
+
index ee61e50..780b1f1 100644 (file)
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -36,12 +36,45 @@ read from the demo file.
 */
 
 /*
 */
 
 /*
+=====================
+CL_NextDemo
+
+Called to play the next demo in the demo loop
+=====================
+*/
+void CL_NextDemo (void)
+{
+       char    str[1024];
+
+       if (cls.demonum == -1)
+               return;         // don't play demos
+
+//     SCR_BeginLoadingPlaque ();
+
+       if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
+       {
+               cls.demonum = 0;
+               if (!cls.demos[cls.demonum][0])
+               {
+                       Con_Printf ("No demos listed with startdemos\n");
+                       cls.demonum = -1;
+                       return;
+               }
+       }
+
+       sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
+       Cbuf_InsertText (str);
+       cls.demonum++;
+}
+
+/*
 ==============
 CL_StopPlayback
 
 Called when a demo file runs out, or the user starts a game
 ==============
 */
 ==============
 CL_StopPlayback
 
 Called when a demo file runs out, or the user starts a game
 ==============
 */
+// LordHavoc: now called only by CL_Disconnect
 void CL_StopPlayback (void)
 {
        if (!cls.demoplayback)
 void CL_StopPlayback (void)
 {
        if (!cls.demoplayback)
@@ -50,7 +83,6 @@ void CL_StopPlayback (void)
        Qclose (cls.demofile);
        cls.demoplayback = false;
        cls.demofile = NULL;
        Qclose (cls.demofile);
        cls.demoplayback = false;
        cls.demofile = NULL;
-       cls.state = ca_disconnected;
 
        if (cls.timedemo)
                CL_FinishTimeDemo ();
 
        if (cls.timedemo)
                CL_FinishTimeDemo ();
@@ -134,7 +166,7 @@ int CL_GetMessage (void)
                r = Qread (cls.demofile, net_message.data, net_message.cursize);
                if (r != net_message.cursize)
                {
                r = Qread (cls.demofile, net_message.data, net_message.cursize);
                if (r != net_message.cursize)
                {
-                       CL_StopPlayback ();
+                       CL_Disconnect ();
                        return 0;
                }
        
                        return 0;
                }
        
index e4b9d4b..be8ab86 100644 (file)
@@ -2,24 +2,6 @@
 
 dlight_t cl_dlights[MAX_DLIGHTS];
 
 
 dlight_t cl_dlights[MAX_DLIGHTS];
 
-void cl_light_start(void)
-{
-}
-
-void cl_light_shutdown(void)
-{
-}
-
-void cl_light_newmap(void)
-{
-       memset (cl_dlights, 0, sizeof(cl_dlights));
-}
-
-void CL_Light_Init(void)
-{
-       R_RegisterModule("CL_Light", cl_light_start, cl_light_shutdown, cl_light_newmap);
-}
-
 /*
 ===============
 CL_AllocDlight
 /*
 ===============
 CL_AllocDlight
@@ -76,7 +58,6 @@ void CL_DecayLights (void)
 
        time = cl.time - cl.oldtime;
 
 
        time = cl.time - cl.oldtime;
 
-       c_dlights = 0;
        dl = cl_dlights;
        for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
        {
        dl = cl_dlights;
        for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
        {
@@ -88,8 +69,6 @@ void CL_DecayLights (void)
                        continue;
                }
 
                        continue;
                }
 
-               c_dlights++; // count every dlight in use
-
                dl->radius -= time*dl->decay;
                if (dl->radius < 0)
                        dl->radius = 0;
                dl->radius -= time*dl->decay;
                if (dl->radius < 0)
                        dl->radius = 0;
index 3843065..f29c25b 100644 (file)
@@ -3,19 +3,25 @@
 #define        MAX_DLIGHTS             256
 typedef struct
 {
 #define        MAX_DLIGHTS             256
 typedef struct
 {
+       // location
        vec3_t  origin;
        vec3_t  origin;
+       // stop lighting after this time
+       float   die;
+       // color of light
+       vec3_t  color;
+       // brightness (not really radius anymore)
        float   radius;
        float   radius;
-       float   die;                    // stop lighting after this time
-       float   decay;                  // drop this each second
-       entity_render_t *ent;   // the entity that spawned this light (can be NULL if it will never be replaced)
-       vec3_t  color;                  // LordHavoc: colored lighting
-} dlight_t;
+       // drop this each second
+       float   decay;
+       // the entity that spawned this light (can be NULL if it will never be replaced)
+       entity_render_t *ent;
+}
+dlight_t;
 
 // LordHavoc: this affects the lighting scale of the whole game
 
 // LordHavoc: this affects the lighting scale of the whole game
-#define LIGHTOFFSET 4096.0f
+#define LIGHTOFFSET 1024.0f
 
 
-extern dlight_t                cl_dlights[MAX_DLIGHTS];
+extern dlight_t cl_dlights[MAX_DLIGHTS];
 
 extern void CL_AllocDlight (entity_render_t *ent, vec3_t org, float radius, float red, float green, float blue, float decay, float lifetime);
 extern void CL_DecayLights (void);
 
 extern void CL_AllocDlight (entity_render_t *ent, vec3_t org, float radius, float red, float green, float blue, float decay, float lifetime);
 extern void CL_DecayLights (void);
-
index 26b78cf..73d7adc 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -25,24 +25,31 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // references them even when on a unix system.
 
 // these two are not intended to be set directly
 // references them even when on a unix system.
 
 // these two are not intended to be set directly
-cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"};
-cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
-cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
+cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"};
+cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
+cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
 
 
-cvar_t cl_shownet = {0, "cl_shownet","0"};
-cvar_t cl_nolerp = {0, "cl_nolerp", "0"};
+cvar_t cl_shownet = {0, "cl_shownet","0"};
+cvar_t cl_nolerp = {0, "cl_nolerp", "0"};
 
 
-cvar_t lookspring = {CVAR_SAVE, "lookspring","0"};
-cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"};
-cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30};
+cvar_t cl_itembobheight = {0, "cl_itembobheight", "8"};
+cvar_t cl_itembobspeed = {0, "cl_itembobspeed", "0.5"};
 
 
-cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"};
-cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"};
-cvar_t m_forward = {CVAR_SAVE, "m_forward","1"};
-cvar_t m_side = {CVAR_SAVE, "m_side","0.8"};
+cvar_t lookspring = {CVAR_SAVE, "lookspring","0"};
+cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"};
+cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30};
+
+cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"};
+cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"};
+cvar_t m_forward = {CVAR_SAVE, "m_forward","1"};
+cvar_t m_side = {CVAR_SAVE, "m_side","0.8"};
 
 cvar_t freelook = {CVAR_SAVE, "freelook", "1"};
 
 
 cvar_t freelook = {CVAR_SAVE, "freelook", "1"};
 
+cvar_t cl_draweffects = {0, "cl_draweffects", "1"};
+
+mempool_t *cl_scores_mempool;
+
 client_static_t        cls;
 client_state_t cl;
 // FIXME: put these on hunk?
 client_static_t        cls;
 client_state_t cl;
 // FIXME: put these on hunk?
@@ -53,6 +60,27 @@ lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
 int                            cl_numvisedicts;
 entity_t               *cl_visedicts[MAX_VISEDICTS];
 
 int                            cl_numvisedicts;
 entity_t               *cl_visedicts[MAX_VISEDICTS];
 
+typedef struct effect_s
+{
+       int active;
+       vec3_t origin;
+       float starttime;
+       float framerate;
+       int modelindex;
+       int startframe;
+       int endframe;
+       // these are for interpolation
+       int frame;
+       double frame1time;
+       double frame2time;
+}
+cl_effect_t;
+
+#define MAX_EFFECTS 256
+
+static cl_effect_t cl_effect[MAX_EFFECTS];
+
+
 /*
 =====================
 CL_ClearState
 /*
 =====================
 CL_ClearState
@@ -66,16 +94,22 @@ void CL_ClearState (void)
        if (!sv.active)
                Host_ClearMemory ();
 
        if (!sv.active)
                Host_ClearMemory ();
 
+       Mem_EmptyPool(cl_scores_mempool);
+
 // wipe the entire cl structure
        memset (&cl, 0, sizeof(cl));
 
        SZ_Clear (&cls.message);
 
 // clear other arrays
 // wipe the entire cl structure
        memset (&cl, 0, sizeof(cl));
 
        SZ_Clear (&cls.message);
 
 // clear other arrays
-       memset (cl_entities, 0, sizeof(cl_entities));
-       memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
-       memset (cl_temp_entities, 0, sizeof(cl_temp_entities));
-       memset (cl_beams, 0, sizeof(cl_beams));
+       memset(cl_entities, 0, sizeof(cl_entities));
+       memset(cl_lightstyle, 0, sizeof(cl_lightstyle));
+       memset(cl_temp_entities, 0, sizeof(cl_temp_entities));
+       memset(cl_beams, 0, sizeof(cl_beams));
+       memset(cl_dlights, 0, sizeof(cl_dlights));
+       memset(cl_effect, 0, sizeof(cl_effect));
+       CL_Particles_Clear();
+       CL_Decals_Clear();
        // LordHavoc: have to set up the baseline info for alpha and other stuff
        for (i = 0;i < MAX_EDICTS;i++)
        {
        // LordHavoc: have to set up the baseline info for alpha and other stuff
        for (i = 0;i < MAX_EDICTS;i++)
        {
@@ -142,7 +176,8 @@ void CL_Disconnect (void)
        cl.cshifts[2].percent = 0;
        cl.cshifts[3].percent = 0;
 
        cl.cshifts[2].percent = 0;
        cl.cshifts[3].percent = 0;
 
-// if running a local server, shut it down
+       cl.worldmodel = NULL;
+
        if (cls.demoplayback)
                CL_StopPlayback ();
        else if (cls.state == ca_connected)
        if (cls.demoplayback)
                CL_StopPlayback ();
        else if (cls.state == ca_connected)
@@ -156,11 +191,11 @@ void CL_Disconnect (void)
                NET_SendUnreliableMessage (cls.netcon, &cls.message);
                SZ_Clear (&cls.message);
                NET_Close (cls.netcon);
                NET_SendUnreliableMessage (cls.netcon, &cls.message);
                SZ_Clear (&cls.message);
                NET_Close (cls.netcon);
-
-               cls.state = ca_disconnected;
+               // if running a local server, shut it down
                if (sv.active)
                        Host_ShutdownServer(false);
        }
                if (sv.active)
                        Host_ShutdownServer(false);
        }
+       cls.state = ca_disconnected;
 
        cls.demoplayback = cls.timedemo = false;
        cls.signon = 0;
 
        cls.demoplayback = cls.timedemo = false;
        cls.signon = 0;
@@ -197,106 +232,23 @@ void CL_EstablishConnection (char *host)
        if (!cls.netcon)
                Host_Error ("CL_Connect: connect failed\n");
        Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
        if (!cls.netcon)
                Host_Error ("CL_Connect: connect failed\n");
        Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
-       
+
        cls.demonum = -1;                       // not in the demo loop now
        cls.state = ca_connected;
        cls.signon = 0;                         // need all the signon messages before playing
 }
 
 /*
        cls.demonum = -1;                       // not in the demo loop now
        cls.state = ca_connected;
        cls.signon = 0;                         // need all the signon messages before playing
 }
 
 /*
-=====================
-CL_SignonReply
-
-An svc_signonnum has been received, perform a client side setup
-=====================
-*/
-void CL_SignonReply (void)
-{
-       char    str[8192];
-
-Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
-
-       switch (cls.signon)
-       {
-       case 1:
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, "prespawn");
-               break;
-
-       case 2:
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
-
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
-       
-               if (cl_pmodel.value)
-               {
-                       MSG_WriteByte (&cls.message, clc_stringcmd);
-                       MSG_WriteString (&cls.message, va("pmodel %f\n", cl_pmodel.value));
-               }
-
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               sprintf (str, "spawn %s", cls.spawnparms);
-               MSG_WriteString (&cls.message, str);
-               break;
-               
-       case 3: 
-               MSG_WriteByte (&cls.message, clc_stringcmd);
-               MSG_WriteString (&cls.message, "begin");
-               Cache_Report ();                // print remaining memory
-               break;
-               
-       case 4:
-//             SCR_EndLoadingPlaque ();                // allow normal screen updates
-               Con_ClearNotify();
-               break;
-       }
-}
-
-/*
-=====================
-CL_NextDemo
-
-Called to play the next demo in the demo loop
-=====================
-*/
-void CL_NextDemo (void)
-{
-       char    str[1024];
-
-       if (cls.demonum == -1)
-               return;         // don't play demos
-
-//     SCR_BeginLoadingPlaque ();
-
-       if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
-       {
-               cls.demonum = 0;
-               if (!cls.demos[cls.demonum][0])
-               {
-                       Con_Printf ("No demos listed with startdemos\n");
-                       cls.demonum = -1;
-                       return;
-               }
-       }
-
-       sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
-       Cbuf_InsertText (str);
-       cls.demonum++;
-}
-
-/*
 ==============
 CL_PrintEntities_f
 ==============
 */
 ==============
 CL_PrintEntities_f
 ==============
 */
-void CL_PrintEntities_f (void)
+static void CL_PrintEntities_f (void)
 {
        entity_t        *ent;
        int                     i, j;
        char            name[32];
 {
        entity_t        *ent;
        int                     i, j;
        char            name[32];
-       
+
        for (i = 0, ent = cl_entities;i < MAX_EDICTS /*cl.num_entities*/;i++, ent++)
        {
                if (!ent->state_current.active)
        for (i = 0, ent = cl_entities;i < MAX_EDICTS /*cl.num_entities*/;i++, ent++)
        {
                if (!ent->state_current.active)
@@ -327,19 +279,19 @@ Determines the fraction between the last two messages that the objects
 should be put at.
 ===============
 */
 should be put at.
 ===============
 */
-float  CL_LerpPoint (void)
+static float CL_LerpPoint (void)
 {
        float   f, frac;
 
        f = cl.mtime[0] - cl.mtime[1];
 
        // LordHavoc: lerp in listen games as the server is being capped below the client (usually)
 {
        float   f, frac;
 
        f = cl.mtime[0] - cl.mtime[1];
 
        // LordHavoc: lerp in listen games as the server is being capped below the client (usually)
-       if (!f || cl_nolerp.value || cls.timedemo || (sv.active && svs.maxclients == 1))
+       if (!f || cl_nolerp.integer || cls.timedemo || (sv.active && svs.maxclients == 1))
        {
                cl.time = cl.mtime[0];
                return 1;
        }
        {
                cl.time = cl.mtime[0];
                return 1;
        }
-               
+
        if (f > 0.1)
        {       // dropped packet, or start of demo
                cl.mtime[1] = cl.mtime[0] - 0.1;
        if (f > 0.1)
        {       // dropped packet, or start of demo
                cl.mtime[1] = cl.mtime[0] - 0.1;
@@ -365,35 +317,18 @@ float     CL_LerpPoint (void)
                }
                frac = 1;
        }
                }
                frac = 1;
        }
-               
-       return frac;
-}
-
-float CL_EntityLerpPoint (entity_t *ent)
-{
-       float   f;
-
-       if (cl_nolerp.value || cls.timedemo || (sv.active && svs.maxclients == 1))
-               return 1;
-
-       f = ent->state_current.time - ent->state_previous.time;
-//     Con_Printf(" %g-%g=%g", ent->state_current.time, ent->state_previous.time, f);
 
 
-       if (f <= 0)
-               return 1;
-       if (f >= 0.1)
-               f = 0.1;
-
-//     Con_Printf(" %g-%g/%g=%f", cl.time, ent->state_previous.time, f, (cl.time - ent->state_previous.time) / f);
-       f = (cl.time - ent->state_previous.time) / f;
-       return bound(0, f, 1);
+       return frac;
 }
 
 }
 
-void CL_RelinkStaticEntities(void)
+static void CL_RelinkStaticEntities(void)
 {
        int i;
        for (i = 0;i < cl.num_statics && cl_numvisedicts < MAX_VISEDICTS;i++)
 {
        int i;
        for (i = 0;i < cl.num_statics && cl_numvisedicts < MAX_VISEDICTS;i++)
+       {
+               Mod_CheckLoaded(cl_static_entities[i].render.model);
                cl_visedicts[cl_numvisedicts++] = &cl_static_entities[i];
                cl_visedicts[cl_numvisedicts++] = &cl_static_entities[i];
+       }
 }
 
 /*
 }
 
 /*
@@ -401,16 +336,18 @@ void CL_RelinkStaticEntities(void)
 CL_RelinkEntities
 ===============
 */
 CL_RelinkEntities
 ===============
 */
-void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent);
-void CL_RelinkNetworkEntities()
+static void CL_RelinkNetworkEntities()
 {
        entity_t        *ent;
 {
        entity_t        *ent;
-       int                     i, j, glowcolor, effects;
-       float           f, d, bobjrotate/*, bobjoffset*/, dlightradius, glowsize;
+       int                     i, glowcolor, effects;
+       float           f, d, bobjrotate, bobjoffset, dlightradius, glowsize, lerp;
        vec3_t          oldorg, neworg, delta, dlightcolor;
 
        bobjrotate = ANGLEMOD(100*cl.time);
        vec3_t          oldorg, neworg, delta, dlightcolor;
 
        bobjrotate = ANGLEMOD(100*cl.time);
-//     bobjoffset = cos(180 * cl.time * M_PI / 180) * 4.0f + 4.0f;
+       if (cl_itembobheight.value)
+               bobjoffset = (cos(cl.time * cl_itembobspeed.value * (2.0 * M_PI)) + 1.0) * 0.5 * cl_itembobheight.value;
+       else
+               bobjoffset = 0;
 
        CL_RelinkStaticEntities();
 
 
        CL_RelinkStaticEntities();
 
@@ -426,19 +363,84 @@ void CL_RelinkNetworkEntities()
                if (!ent->state_previous.active)
                {
                        // only one state available
                if (!ent->state_previous.active)
                {
                        // only one state available
+                       lerp = 1;
+                       VectorCopy (ent->state_current.origin, oldorg); // skip trails
                        VectorCopy (ent->state_current.origin, neworg);
                        VectorCopy (ent->state_current.angles, ent->render.angles);
                        VectorCopy (ent->state_current.origin, neworg);
                        VectorCopy (ent->state_current.angles, ent->render.angles);
+
+                       /*
+                       // monster interpolation
+                       ent->persistent.steplerptime = 0;
+                       VectorCopy(ent->state_current.origin, ent->persistent.stepoldorigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepoldangles);
+                       VectorCopy(ent->state_current.origin, ent->persistent.steporigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepangles);
+                       */
+               }
+               /*
+               else if ((ent->state_current.flags & ent->state_previous.flags) & ENTFLAG_STEP)
+               {
+                       if (ent->state_current.origin[0] != ent->persistent.steporigin[0]
+                        || ent->state_current.origin[1] != ent->persistent.steporigin[1]
+                        || ent->state_current.origin[2] != ent->persistent.steporigin[2]
+                        || ent->state_current.angles[0] != ent->persistent.stepangles[0]
+                        || ent->state_current.angles[1] != ent->persistent.stepangles[1]
+                        || ent->state_current.angles[2] != ent->persistent.stepangles[2])
+                       {
+                               // update lerp positions
+                               ent->clientpersistent.steplerptime = sv.time;
+                               VectorCopy(ent->steporigin, ent->stepoldorigin);
+                               VectorCopy(ent->stepangles, ent->stepoldangles);
+                               VectorCopy(ent->v.origin, ent->steporigin);
+                               VectorCopy(ent->v.angles, ent->stepangles);
+                       }
+                       lerp = (cl.time - ent->persistent.steplerptime) * 10.0;
+                       if (lerp < 1)
+                       {
+                               // origin
+                               VectorSubtract(ent->persistent.steporigin, ent->persistent.stepoldorigin, delta);
+                               VectorMA(ent->persistent.stepoldorigin, lerp, delta, neworg);
+
+                               // angles
+                               VectorSubtract(ent->persistent.stepangles, ent->persistent.stepoldangles, delta);
+                               // choose shortest rotate (to avoid 'spin around' situations)
+                               if (delta[0] < -180) delta[0] += 360;else if (delta[0] >= 180) delta[0] -= 360;
+                               if (delta[1] < -180) delta[1] += 360;else if (delta[1] >= 180) delta[1] -= 360;
+                               if (delta[2] < -180) delta[2] += 360;else if (delta[2] >= 180) delta[2] -= 360;
+                               VectorMA(ent->stepoldangles, lerp, delta, ent->render.angles);
+                       }
+                       else
+                       {
+                               VectorCopy(ent->persistent.steporigin, neworg);
+                               VectorCopy(ent->persistent.stepangles, ent->render.angles);
+                       }
                }
                }
+               */
                else
                {
                else
                {
+                       /*
+                       // monster interpolation
+                       ent->persistent.steplerptime = 0;
+                       VectorCopy(ent->state_current.origin, ent->persistent.stepoldorigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepoldangles);
+                       VectorCopy(ent->state_current.origin, ent->persistent.steporigin);
+                       VectorCopy(ent->state_current.angles, ent->persistent.stepangles);
+                       */
+
                        // if the delta is large, assume a teleport and don't lerp
                        VectorSubtract(ent->state_current.origin, ent->state_previous.origin, delta);
                        // LordHavoc: increased tolerance from 100 to 200
                        // if the delta is large, assume a teleport and don't lerp
                        VectorSubtract(ent->state_current.origin, ent->state_previous.origin, delta);
                        // LordHavoc: increased tolerance from 100 to 200
-                       if (DotProduct(delta, delta) > 200*200)
-                               f = 1;
+                       if ((sv.active && svs.maxclients == 1 && !(ent->state_current.flags & RENDER_STEP)) || cls.timedemo || DotProduct(delta, delta) > 200*200 || cl_nolerp.integer)
+                               lerp = 1;
                        else
                        else
-                               f = CL_EntityLerpPoint(ent);
-                       if (f >= 1)
+                       {
+                               f = ent->state_current.time - ent->state_previous.time;
+                               if (f > 0)
+                                       lerp = (cl.time - ent->state_previous.time) / f;
+                               else
+                                       lerp = 1;
+                       }
+                       if (lerp >= 1)
                        {
                                // no interpolation
                                VectorCopy (ent->state_current.origin, neworg);
                        {
                                // no interpolation
                                VectorCopy (ent->state_current.origin, neworg);
@@ -447,29 +449,25 @@ void CL_RelinkNetworkEntities()
                        else
                        {
                                // interpolate the origin and angles
                        else
                        {
                                // interpolate the origin and angles
-                               for (j = 0;j < 3;j++)
-                               {
-                                       neworg[j] = ent->state_previous.origin[j] + f*delta[j];
-
-                                       d = ent->state_current.angles[j] - ent->state_previous.angles[j];
-                                       if (d > 180)
-                                               d -= 360;
-                                       else if (d < -180)
-                                               d += 360;
-                                       ent->render.angles[j] = ent->state_previous.angles[j] + f*d;
-                               }
+                               VectorMA(ent->state_previous.origin, lerp, delta, neworg);
+                               VectorSubtract(ent->state_current.angles, ent->state_previous.angles, delta);
+                               if (delta[0] < -180) delta[0] += 360;else if (delta[0] >= 180) delta[0] -= 360;
+                               if (delta[1] < -180) delta[1] += 360;else if (delta[1] >= 180) delta[1] -= 360;
+                               if (delta[2] < -180) delta[2] += 360;else if (delta[2] >= 180) delta[2] -= 360;
+                               VectorMA(ent->state_previous.angles, lerp, delta, ent->render.angles);
                        }
                }
 
                VectorCopy (neworg, ent->persistent.trail_origin);
                // persistent.modelindex will be updated by CL_LerpUpdate
                        }
                }
 
                VectorCopy (neworg, ent->persistent.trail_origin);
                // persistent.modelindex will be updated by CL_LerpUpdate
-               if (ent->state_current.modelindex != ent->persistent.modelindex)
+               if (ent->state_current.modelindex != ent->persistent.modelindex || !ent->state_previous.active)
                        VectorCopy(neworg, oldorg);
 
                VectorCopy (neworg, ent->render.origin);
                ent->render.flags = ent->state_current.flags;
                ent->render.effects = effects = ent->state_current.effects;
                ent->render.model = cl.model_precache[ent->state_current.modelindex];
                        VectorCopy(neworg, oldorg);
 
                VectorCopy (neworg, ent->render.origin);
                ent->render.flags = ent->state_current.flags;
                ent->render.effects = effects = ent->state_current.effects;
                ent->render.model = cl.model_precache[ent->state_current.modelindex];
+               Mod_CheckLoaded(ent->render.model);
                ent->render.frame = ent->state_current.frame;
                if (cl.scores == NULL || !ent->state_current.colormap)
                        ent->render.colormap = -1; // no special coloring
                ent->render.frame = ent->state_current.frame;
                if (cl.scores == NULL || !ent->state_current.colormap)
                        ent->render.colormap = -1; // no special coloring
@@ -480,9 +478,6 @@ void CL_RelinkNetworkEntities()
                ent->render.scale = ent->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate?
                glowsize = ent->state_current.glowsize * 4.0f; // FIXME: interpolate?
                glowcolor = ent->state_current.glowcolor;
                ent->render.scale = ent->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate?
                glowsize = ent->state_current.glowsize * 4.0f; // FIXME: interpolate?
                glowcolor = ent->state_current.glowcolor;
-               ent->render.colormod[0] = (float) ((ent->state_current.colormod >> 5) & 7) * (1.0f / 7.0f);
-               ent->render.colormod[1] = (float) ((ent->state_current.colormod >> 2) & 7) * (1.0f / 7.0f);
-               ent->render.colormod[2] = (float) (ent->state_current.colormod & 3) * (1.0f / 3.0f);
 
                // update interpolation info
                CL_LerpUpdate(ent, ent->state_current.frame, ent->state_current.modelindex);
 
                // update interpolation info
                CL_LerpUpdate(ent, ent->state_current.frame, ent->state_current.modelindex);
@@ -497,7 +492,7 @@ void CL_RelinkNetworkEntities()
                if (effects)
                {
                        if (effects & EF_BRIGHTFIELD)
                if (effects)
                {
                        if (effects & EF_BRIGHTFIELD)
-                               R_EntityParticles (ent);
+                               CL_EntityParticles (ent);
                        if (effects & EF_MUZZLEFLASH)
                        {
                                vec3_t v, v2;
                        if (effects & EF_MUZZLEFLASH)
                        {
                                vec3_t v, v2;
@@ -559,7 +554,7 @@ void CL_RelinkNetworkEntities()
                                        }
                                        // how many flames to make
                                        temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300);
                                        }
                                        // how many flames to make
                                        temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300);
-                                       R_FlameCube(mins, maxs, temp);
+                                       CL_FlameCube(mins, maxs, temp);
                                }
                                d = lhrandom(200, 250);
                                dlightcolor[0] += d * 1.0f;
                                }
                                d = lhrandom(200, 250);
                                dlightcolor[0] += d * 1.0f;
@@ -574,22 +569,22 @@ void CL_RelinkNetworkEntities()
                        if (ent->render.model->flags & EF_ROTATE)
                        {
                                ent->render.angles[1] = bobjrotate;
                        if (ent->render.model->flags & EF_ROTATE)
                        {
                                ent->render.angles[1] = bobjrotate;
-//                             ent->render.origin[2] += bobjoffset;
+                               ent->render.origin[2] += bobjoffset;
                        }
                        // only do trails if present in the previous frame as well
                        if (ent->state_previous.active)
                        {
                                if (ent->render.model->flags & EF_GIB)
                        }
                        // only do trails if present in the previous frame as well
                        if (ent->state_previous.active)
                        {
                                if (ent->render.model->flags & EF_GIB)
-                                       R_RocketTrail (oldorg, neworg, 2, ent);
+                                       CL_RocketTrail (oldorg, neworg, 2, ent);
                                else if (ent->render.model->flags & EF_ZOMGIB)
                                else if (ent->render.model->flags & EF_ZOMGIB)
-                                       R_RocketTrail (oldorg, neworg, 4, ent);
+                                       CL_RocketTrail (oldorg, neworg, 4, ent);
                                else if (ent->render.model->flags & EF_TRACER)
                                else if (ent->render.model->flags & EF_TRACER)
-                                       R_RocketTrail (oldorg, neworg, 3, ent);
+                                       CL_RocketTrail (oldorg, neworg, 3, ent);
                                else if (ent->render.model->flags & EF_TRACER2)
                                else if (ent->render.model->flags & EF_TRACER2)
-                                       R_RocketTrail (oldorg, neworg, 5, ent);
+                                       CL_RocketTrail (oldorg, neworg, 5, ent);
                                else if (ent->render.model->flags & EF_ROCKET)
                                {
                                else if (ent->render.model->flags & EF_ROCKET)
                                {
-                                       R_RocketTrail (oldorg, ent->render.origin, 0, ent);
+                                       CL_RocketTrail (oldorg, ent->render.origin, 0, ent);
                                        dlightcolor[0] += 200.0f;
                                        dlightcolor[1] += 160.0f;
                                        dlightcolor[2] +=  80.0f;
                                        dlightcolor[0] += 200.0f;
                                        dlightcolor[1] += 160.0f;
                                        dlightcolor[2] +=  80.0f;
@@ -597,12 +592,12 @@ void CL_RelinkNetworkEntities()
                                else if (ent->render.model->flags & EF_GRENADE)
                                {
                                        if (ent->render.alpha == -1) // LordHavoc: Nehahra dem compatibility
                                else if (ent->render.model->flags & EF_GRENADE)
                                {
                                        if (ent->render.alpha == -1) // LordHavoc: Nehahra dem compatibility
-                                               R_RocketTrail (oldorg, neworg, 7, ent);
+                                               CL_RocketTrail (oldorg, neworg, 7, ent);
                                        else
                                        else
-                                               R_RocketTrail (oldorg, neworg, 1, ent);
+                                               CL_RocketTrail (oldorg, neworg, 1, ent);
                                }
                                else if (ent->render.model->flags & EF_TRACER3)
                                }
                                else if (ent->render.model->flags & EF_TRACER3)
-                                       R_RocketTrail (oldorg, neworg, 6, ent);
+                                       CL_RocketTrail (oldorg, neworg, 6, ent);
                        }
                }
                // LordHavoc: customizable glow
                        }
                }
                // LordHavoc: customizable glow
@@ -615,7 +610,7 @@ void CL_RelinkNetworkEntities()
                }
                // LordHavoc: customizable trail
                if (ent->render.flags & RENDER_GLOWTRAIL)
                }
                // LordHavoc: customizable trail
                if (ent->render.flags & RENDER_GLOWTRAIL)
-                       R_RocketTrail2 (oldorg, neworg, glowcolor, ent);
+                       CL_RocketTrail2 (oldorg, neworg, glowcolor, ent);
 
                if (dlightcolor[0] || dlightcolor[1] || dlightcolor[2])
                {
 
                if (dlightcolor[0] || dlightcolor[1] || dlightcolor[2])
                {
@@ -624,12 +619,12 @@ void CL_RelinkNetworkEntities()
                        d = 1.0f / dlightradius;
                        VectorCopy(neworg, vec);
                        // hack to make glowing player light shine on their gun
                        d = 1.0f / dlightradius;
                        VectorCopy(neworg, vec);
                        // hack to make glowing player light shine on their gun
-                       if (i == cl.viewentity && !chase_active.value)
+                       if (i == cl.viewentity && !chase_active.integer)
                                vec[2] += 30;
                        CL_AllocDlight (&ent->render, vec, dlightradius, dlightcolor[0] * d, dlightcolor[1] * d, dlightcolor[2] * d, 0, 0);
                }
 
                                vec[2] += 30;
                        CL_AllocDlight (&ent->render, vec, dlightradius, dlightcolor[0] * d, dlightcolor[1] * d, dlightcolor[2] * d, 0, 0);
                }
 
-               if (chase_active.value)
+               if (chase_active.integer)
                {
                        if (ent->render.flags & RENDER_VIEWMODEL)
                                continue;
                {
                        if (ent->render.flags & RENDER_VIEWMODEL)
                                continue;
@@ -649,7 +644,7 @@ void CL_RelinkNetworkEntities()
        }
 }
 
        }
 }
 
-void CL_LerpPlayerVelocity (void)
+static void CL_LerpPlayerVelocity (void)
 {
        int i;
        float frac, d;
 {
        int i;
        float frac, d;
@@ -675,12 +670,90 @@ void CL_LerpPlayerVelocity (void)
        }
 }
 
        }
 }
 
+void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate)
+{
+       int i;
+       cl_effect_t *e;
+       if (!modelindex) // sanity check
+               return;
+       for (i = 0, e = cl_effect;i < MAX_EFFECTS;i++, e++)
+       {
+               if (e->active)
+                       continue;
+               e->active = true;
+               VectorCopy(org, e->origin);
+               e->modelindex = modelindex;
+               e->starttime = cl.time;
+               e->startframe = startframe;
+               e->endframe = startframe + framecount;
+               e->framerate = framerate;
+
+               e->frame = 0;
+               e->frame1time = cl.time;
+               e->frame2time = cl.time;
+               break;
+       }
+}
+
+static void CL_RelinkEffects()
+{
+       int i, intframe;
+       cl_effect_t *e;
+       entity_t *vis;
+       float frame;
+
+       for (i = 0, e = cl_effect;i < MAX_EFFECTS;i++, e++)
+       {
+               if (e->active)
+               {
+                       frame = (cl.time - e->starttime) * e->framerate + e->startframe;
+                       intframe = frame;
+                       if (intframe < 0 || intframe >= e->endframe)
+                       {
+                               e->active = false;
+                               memset(e, 0, sizeof(*e));
+                               continue;
+                       }
+
+                       if (intframe != e->frame)
+                       {
+                               e->frame = intframe;
+                               e->frame1time = e->frame2time;
+                               e->frame2time = cl.time;
+                       }
+
+                       if ((vis = CL_NewTempEntity()))
+                       {
+                               // interpolation stuff
+                               vis->render.frame1 = intframe;
+                               vis->render.frame2 = intframe + 1;
+                               if (vis->render.frame2 >= e->endframe)
+                                       vis->render.frame2 = -1; // disappear
+                               vis->render.framelerp = frame - intframe;
+                               vis->render.frame1time = e->frame1time;
+                               vis->render.frame2time = e->frame2time;
+
+                               // normal stuff
+                               VectorCopy(e->origin, vis->render.origin);
+                               vis->render.model = cl.model_precache[e->modelindex];
+                               vis->render.frame = vis->render.frame2;
+                               vis->render.colormap = -1; // no special coloring
+                               vis->render.scale = 1;
+                               vis->render.alpha = 1;
+                       }
+               }
+       }
+}
+
 void CL_RelinkEntities (void)
 {
        cl_numvisedicts = 0;
 
        CL_LerpPlayerVelocity();
        CL_RelinkNetworkEntities();
 void CL_RelinkEntities (void)
 {
        cl_numvisedicts = 0;
 
        CL_LerpPlayerVelocity();
        CL_RelinkNetworkEntities();
+       CL_RelinkEffects();
+       CL_MoveParticles();
+       CL_UpdateDecals();
 }
 
 
 }
 
 
@@ -697,7 +770,7 @@ int CL_ReadFromServer (void)
 
        cl.oldtime = cl.time;
        cl.time += cl.frametime;
 
        cl.oldtime = cl.time;
        cl.time += cl.frametime;
-       
+
        netshown = false;
        do
        {
        netshown = false;
        do
        {
@@ -706,22 +779,21 @@ int CL_ReadFromServer (void)
                        Host_Error ("CL_ReadFromServer: lost server connection");
                if (!ret)
                        break;
                        Host_Error ("CL_ReadFromServer: lost server connection");
                if (!ret)
                        break;
-               
+
                cl.last_received_message = realtime;
 
                cl.last_received_message = realtime;
 
-               if (cl_shownet.value)
+               if (cl_shownet.integer)
                        netshown = true;
 
                CL_ParseServerMessage ();
        }
        while (ret && cls.state == ca_connected);
                        netshown = true;
 
                CL_ParseServerMessage ();
        }
        while (ret && cls.state == ca_connected);
-       
+
        if (netshown)
                Con_Printf ("\n");
 
        CL_RelinkEntities ();
        CL_UpdateTEnts ();
        if (netshown)
                Con_Printf ("\n");
 
        CL_RelinkEntities ();
        CL_UpdateTEnts ();
-       CL_DoEffects ();
 
 //
 // bring the links up to date
 
 //
 // bring the links up to date
@@ -748,7 +820,7 @@ void CL_SendCmd (void)
 
        // allow mice or other external controllers to add to the move
                IN_Move (&cmd);
 
        // allow mice or other external controllers to add to the move
                IN_Move (&cmd);
-       
+
        // send the unreliable message
                CL_SendMove (&cmd);
        }
        // send the unreliable message
                CL_SendMove (&cmd);
        }
@@ -758,11 +830,11 @@ void CL_SendCmd (void)
                SZ_Clear (&cls.message);
                return;
        }
                SZ_Clear (&cls.message);
                return;
        }
-       
+
 // send the reliable message
        if (!cls.message.cursize)
                return;         // no message at all
 // send the reliable message
        if (!cls.message.cursize)
                return;         // no message at all
-       
+
        if (!NET_CanSendMessage (cls.netcon))
        {
                Con_DPrintf ("CL_WriteToServer: can't send\n");
        if (!NET_CanSendMessage (cls.netcon))
        {
                Con_DPrintf ("CL_WriteToServer: can't send\n");
@@ -776,7 +848,7 @@ void CL_SendCmd (void)
 }
 
 // LordHavoc: pausedemo command
 }
 
 // LordHavoc: pausedemo command
-void CL_PauseDemo_f (void)
+static void CL_PauseDemo_f (void)
 {
        cls.demopaused = !cls.demopaused;
        if (cls.demopaused)
 {
        cls.demopaused = !cls.demopaused;
        if (cls.demopaused)
@@ -791,7 +863,7 @@ CL_PModel_f
 LordHavoc: Intended for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
 ======================
 */
 LordHavoc: Intended for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
 ======================
 */
-void CL_PModel_f (void)
+static void CL_PModel_f (void)
 {
        int i;
        eval_t *val;
 {
        int i;
        eval_t *val;
@@ -805,7 +877,7 @@ void CL_PModel_f (void)
 
        if (cmd_source == src_command)
        {
 
        if (cmd_source == src_command)
        {
-               if (cl_pmodel.value == i)
+               if (cl_pmodel.integer == i)
                        return;
                Cvar_SetValue ("_cl_pmodel", i);
                if (cls.state == ca_connected)
                        return;
                Cvar_SetValue ("_cl_pmodel", i);
                if (cls.state == ca_connected)
@@ -823,7 +895,7 @@ void CL_PModel_f (void)
 CL_Fog_f
 ======================
 */
 CL_Fog_f
 ======================
 */
-void CL_Fog_f (void)
+static void CL_Fog_f (void)
 {
        if (Cmd_Argc () == 1)
        {
 {
        if (Cmd_Argc () == 1)
        {
@@ -842,18 +914,19 @@ CL_Init
 =================
 */
 void CL_Init (void)
 =================
 */
 void CL_Init (void)
-{      
-       SZ_Alloc (&cls.message, 1024);
+{
+       SZ_Alloc (&cls.message, 1024, "cls.message");
 
        CL_InitInput ();
        CL_InitTEnts ();
 
        CL_InitInput ();
        CL_InitTEnts ();
-       
+
 //
 // register our commands
 //
        Cvar_RegisterVariable (&cl_name);
        Cvar_RegisterVariable (&cl_color);
 //
 // register our commands
 //
        Cvar_RegisterVariable (&cl_name);
        Cvar_RegisterVariable (&cl_color);
-       Cvar_RegisterVariable (&cl_pmodel);
+       if (gamemode == GAME_NEHAHRA)
+               Cvar_RegisterVariable (&cl_pmodel);
        Cvar_RegisterVariable (&cl_upspeed);
        Cvar_RegisterVariable (&cl_forwardspeed);
        Cvar_RegisterVariable (&cl_backspeed);
        Cvar_RegisterVariable (&cl_upspeed);
        Cvar_RegisterVariable (&cl_forwardspeed);
        Cvar_RegisterVariable (&cl_backspeed);
@@ -874,8 +947,9 @@ void CL_Init (void)
        Cvar_RegisterVariable (&m_forward);
        Cvar_RegisterVariable (&m_side);
 
        Cvar_RegisterVariable (&m_forward);
        Cvar_RegisterVariable (&m_side);
 
-//     Cvar_RegisterVariable (&cl_autofire);
-       
+       Cvar_RegisterVariable (&cl_itembobspeed);
+       Cvar_RegisterVariable (&cl_itembobheight);
+
        Cmd_AddCommand ("entities", CL_PrintEntities_f);
        Cmd_AddCommand ("bitprofile", CL_BitProfile_f);
        Cmd_AddCommand ("disconnect", CL_Disconnect_f);
        Cmd_AddCommand ("entities", CL_PrintEntities_f);
        Cmd_AddCommand ("bitprofile", CL_BitProfile_f);
        Cmd_AddCommand ("disconnect", CL_Disconnect_f);
@@ -888,8 +962,14 @@ void CL_Init (void)
 
        // LordHavoc: added pausedemo
        Cmd_AddCommand ("pausedemo", CL_PauseDemo_f);
 
        // LordHavoc: added pausedemo
        Cmd_AddCommand ("pausedemo", CL_PauseDemo_f);
-       // LordHavoc: added pmodel command (like name, etc, only intended for Nehahra)
-       Cmd_AddCommand ("pmodel", CL_PModel_f);
+       if (gamemode == GAME_NEHAHRA)
+               Cmd_AddCommand ("pmodel", CL_PModel_f);
+
+       cl_scores_mempool = Mem_AllocPool("client player info");
+
+       Cvar_RegisterVariable(&cl_draweffects);
 
        CL_Parse_Init();
 
        CL_Parse_Init();
+       CL_Particles_Init();
+       CL_Decals_Init();
 }
 }
index ec3d3d5..9a06ee4 100644 (file)
@@ -8,7 +8,7 @@ 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
 
 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.  
+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.
 
@@ -273,19 +273,17 @@ void CL_ParseEntityLump(char *entdata)
 {
        char *data;
        char key[128], value[4096];
 {
        char *data;
        char key[128], value[4096];
-       char wadname[128];
        char targetnamebuffer[65536];
        char *targetname[8192], *target[MAX_STATICLIGHTS], light_target[256];
        vec3_t targetnameorigin[8192], targetnametemporigin, v;
        int targets, targetnames, targetnamebufferpos, targetnameorigintofillin;
        char targetnamebuffer[65536];
        char *targetname[8192], *target[MAX_STATICLIGHTS], light_target[256];
        vec3_t targetnameorigin[8192], targetnametemporigin, v;
        int targets, targetnames, targetnamebufferpos, targetnameorigintofillin;
-       int i, j, k, n;
+       int i, j, n;
        float f1, f2, f3, f4;
        float ambientlight, ambientcolor[3], sunlight, sunlightdirection[3], sunlightcolor[3];
        int light_fadetype, light_style, hlight, tyrlite, light_enable;
        float light_origin[3], light_light, light_distancescale, light_lightcolor[3], light_color[3], light_direction[3], light_cone, light_lightradius;
        FOG_clear(); // LordHavoc: no fog until set
        R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
        float f1, f2, f3, f4;
        float ambientlight, ambientcolor[3], sunlight, sunlightdirection[3], sunlightcolor[3];
        int light_fadetype, light_style, hlight, tyrlite, light_enable;
        float light_origin[3], light_light, light_distancescale, light_lightcolor[3], light_color[3], light_direction[3], light_cone, light_lightradius;
        FOG_clear(); // LordHavoc: no fog until set
        R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
-       r_farclip.value = 6144; // LordHavoc: default farclip distance
        r_sunlightenabled = false;
        staticlights = 0;
        data = entdata;
        r_sunlightenabled = false;
        staticlights = 0;
        data = entdata;
@@ -335,12 +333,6 @@ void CL_ParseEntityLump(char *entdata)
                        R_SetSkyBox(value);
                else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
                        R_SetSkyBox(value);
                        R_SetSkyBox(value);
                else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
                        R_SetSkyBox(value);
-               else if (!strcmp("farclip", key))
-               {
-                       r_farclip.value = atof(value);
-                       if (r_farclip.value < 64)
-                               r_farclip.value = 64;
-               }
                else if (!strcmp("fog", key))
                        scanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
                else if (!strcmp("fog_density", key))
                else if (!strcmp("fog", key))
                        scanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
                else if (!strcmp("fog_density", key))
@@ -351,36 +343,6 @@ void CL_ParseEntityLump(char *entdata)
                        fog_green = atof(value);
                else if (!strcmp("fog_blue", key))
                        fog_blue = atof(value);
                        fog_green = atof(value);
                else if (!strcmp("fog_blue", key))
                        fog_blue = atof(value);
-               else if (!strcmp("wad", key)) // for HalfLife maps
-               {
-                       if (hlbsp)
-                       {
-                               j = 0;
-                               for (i = 0;i < 4096;i++)
-                                       if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
-                                               break;
-                               if (value[i])
-                               {
-                                       for (;i < 4096;i++)
-                                       {
-                                               // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
-                                               if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
-                                                       j = i+1;
-                                               else if (value[i] == ';' || value[i] == 0)
-                                               {
-                                                       k = value[i];
-                                                       value[i] = 0;
-                                                       strcpy(wadname, "textures/");
-                                                       strcat(wadname, &value[j]);
-                                                       W_LoadTextureWadFile (wadname, false);
-                                                       j = i+1;
-                                                       if (!k)
-                                                               break;
-                                               }
-                                       }
-                               }
-                       }
-               }
                else if (!strcmp("light", key))
                        ambientlight = atof(value);
                else if (!strcmp("sunlight", key))
                else if (!strcmp("light", key))
                        ambientlight = atof(value);
                else if (!strcmp("sunlight", key))
@@ -590,7 +552,7 @@ void CL_ParseEntityLump(char *entdata)
                        staticlights++;
                }
        }
                        staticlights++;
                }
        }
-       if (hlbsp)
+       if (cl.worldmodel->ishlbsp)
                n = LIGHTFADE_LDIVX2;
        else if (tyrlite)
                n = LIGHTFADE_LMINUSX;
                n = LIGHTFADE_LDIVX2;
        else if (tyrlite)
                n = LIGHTFADE_LMINUSX;
@@ -621,6 +583,56 @@ void CL_ParseEntityLump(char *entdata)
 }
 
 /*
 }
 
 /*
+=====================
+CL_SignonReply
+
+An svc_signonnum has been received, perform a client side setup
+=====================
+*/
+static void CL_SignonReply (void)
+{
+       char    str[8192];
+
+Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
+
+       switch (cls.signon)
+       {
+       case 1:
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, "prespawn");
+               break;
+
+       case 2:
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
+
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
+
+               if (cl_pmodel.integer)
+               {
+                       MSG_WriteByte (&cls.message, clc_stringcmd);
+                       MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
+               }
+
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               sprintf (str, "spawn %s", cls.spawnparms);
+               MSG_WriteString (&cls.message, str);
+               break;
+
+       case 3:
+               MSG_WriteByte (&cls.message, clc_stringcmd);
+               MSG_WriteString (&cls.message, "begin");
+               break;
+
+       case 4:
+//             SCR_EndLoadingPlaque ();                // allow normal screen updates
+               Con_ClearNotify();
+               break;
+       }
+}
+
+/*
 ==================
 CL_ParseServerInfo
 ==================
 ==================
 CL_ParseServerInfo
 ==================
@@ -649,7 +661,7 @@ void CL_ParseServerInfo (void)
        Nehahrademcompatibility = false;
        if (i == 250)
                Nehahrademcompatibility = true;
        Nehahrademcompatibility = false;
        if (i == 250)
                Nehahrademcompatibility = true;
-       if (cls.demoplayback && demo_nehahra.value)
+       if (cls.demoplayback && demo_nehahra.integer)
                Nehahrademcompatibility = true;
        dpprotocol = i == DPPROTOCOL_VERSION;
 
                Nehahrademcompatibility = true;
        dpprotocol = i == DPPROTOCOL_VERSION;
 
@@ -660,7 +672,7 @@ void CL_ParseServerInfo (void)
                Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
                return;
        }
                Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
                return;
        }
-       cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
+       cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
 
 // parse gametype
        cl.gametype = MSG_ReadByte ();
 
 // parse gametype
        cl.gametype = MSG_ReadByte ();
@@ -682,7 +694,11 @@ void CL_ParseServerInfo (void)
 // needlessly purge it
 //
 
 // needlessly purge it
 //
 
-       Hunk_Check ();
+       Mem_CheckSentinelsGlobal();
+
+       Mod_ClearUsed();
+
+       Mem_CheckSentinelsGlobal();
 
 // precache models
        memset (cl.model_precache, 0, sizeof(cl.model_precache));
 
 // precache models
        memset (cl.model_precache, 0, sizeof(cl.model_precache));
@@ -700,9 +716,6 @@ void CL_ParseServerInfo (void)
                        Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
                strcpy (model_precache[nummodels], str);
                Mod_TouchModel (str);
                        Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
                strcpy (model_precache[nummodels], str);
                Mod_TouchModel (str);
-
-//             Hunk_Check ();
-
        }
 
 // precache sounds
        }
 
 // precache sounds
@@ -723,18 +736,20 @@ void CL_ParseServerInfo (void)
                S_TouchSound (str);
        }
 
                S_TouchSound (str);
        }
 
+       Mem_CheckSentinelsGlobal();
+
+       Mod_PurgeUnused();
+
 //
 // now we try to load everything else until a cache allocation fails
 //
 
 //
 // now we try to load everything else until a cache allocation fails
 //
 
-       Hunk_Check ();
+       Mem_CheckSentinelsGlobal();
 
        for (i=1 ; i<nummodels ; i++)
        {
 
        for (i=1 ; i<nummodels ; i++)
        {
-               isworldmodel = i == 1; // LordHavoc: first model is the world model
-               cl.model_precache[i] = Mod_ForName (model_precache[i], false);
-
-//             Hunk_Check ();
+               // LordHavoc: i == 1 means the first model is the world model
+               cl.model_precache[i] = Mod_ForName (model_precache[i], false, true, i == 1);
 
                if (cl.model_precache[i] == NULL)
                {
 
                if (cl.model_precache[i] == NULL)
                {
@@ -744,7 +759,7 @@ void CL_ParseServerInfo (void)
                CL_KeepaliveMessage ();
        }
 
                CL_KeepaliveMessage ();
        }
 
-       Hunk_Check ();
+       Mem_CheckSentinelsGlobal();
 
        S_BeginPrecaching ();
        for (i=1 ; i<numsounds ; i++)
 
        S_BeginPrecaching ();
        for (i=1 ; i<numsounds ; i++)
@@ -754,15 +769,14 @@ void CL_ParseServerInfo (void)
        }
        S_EndPrecaching ();
 
        }
        S_EndPrecaching ();
 
-
 // local state
        cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
 // local state
        cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
-
-//     Hunk_Check ();
+       cl_entities[0].render.scale = 1;
+       cl_entities[0].render.alpha = 1;
 
        R_NewMap ();
 
 
        R_NewMap ();
 
-       Hunk_Check ();          // make sure nothing is hurt
+       Mem_CheckSentinelsGlobal();
 
        noclip_anglehack = false;               // noclip is turned off at start
 }
 
        noclip_anglehack = false;               // noclip is turned off at start
 }
@@ -782,14 +796,15 @@ void CL_ValidateState(entity_state_t *s)
                Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
 
        model = cl.model_precache[s->modelindex];
                Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
 
        model = cl.model_precache[s->modelindex];
+       Mod_CheckLoaded(model);
        if (model && s->frame >= model->numframes)
        {
        if (model && s->frame >= model->numframes)
        {
-               Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
+               Con_Printf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
                s->frame = 0;
        }
                s->frame = 0;
        }
-       if (model && s->skin >= model->numskins)
+       if (model && s->skin > 0 && s->skin >= model->numskins)
        {
        {
-               Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
+               Con_Printf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
                s->skin = 0;
        }
 }
                s->skin = 0;
        }
 }
@@ -809,6 +824,7 @@ void CL_ParseUpdate (int bits)
 {
        int i, num, deltadie;
        entity_t *ent;
 {
        int i, num, deltadie;
        entity_t *ent;
+       entity_state_t new;
 
        if (cls.signon == SIGNONS - 1)
        {       // first update is the final signon stage
 
        if (cls.signon == SIGNONS - 1)
        {       // first update is the final signon stage
@@ -825,7 +841,7 @@ void CL_ParseUpdate (int bits)
                        bits |= MSG_ReadByte() << 24;
        }
 
                        bits |= MSG_ReadByte() << 24;
        }
 
-       if (bits & U_LONGENTITY)        
+       if (bits & U_LONGENTITY)
                num = (unsigned) MSG_ReadShort ();
        else
                num = (unsigned) MSG_ReadByte ();
                num = (unsigned) MSG_ReadShort ();
        else
                num = (unsigned) MSG_ReadByte ();
@@ -845,43 +861,48 @@ void CL_ParseUpdate (int bits)
                        bitprofile[i]++;
        bitprofilecount++;
 
                        bitprofile[i]++;
        bitprofilecount++;
 
-       ent->state_previous = ent->state_current;
        deltadie = false;
        if (bits & U_DELTA)
        {
        deltadie = false;
        if (bits & U_DELTA)
        {
-               if (!ent->state_current.active)
+               new = ent->state_current;
+               if (!new.active)
                        deltadie = true; // was not present in previous frame, leave hidden until next full update
        }
        else
                        deltadie = true; // was not present in previous frame, leave hidden until next full update
        }
        else
-               ent->state_current = ent->state_baseline;
-
-       ent->state_current.time = cl.mtime[0];
-
-       ent->state_current.flags = 0;
-       ent->state_current.active = true;
-       if (bits & U_MODEL)             ent->state_current.modelindex = (ent->state_current.modelindex & 0xFF00) | MSG_ReadByte();
-       if (bits & U_FRAME)             ent->state_current.frame = (ent->state_current.frame & 0xFF00) | MSG_ReadByte();
-       if (bits & U_COLORMAP)  ent->state_current.colormap = MSG_ReadByte();
-       if (bits & U_SKIN)              ent->state_current.skin = MSG_ReadByte();
-       if (bits & U_EFFECTS)   ent->state_current.effects = (ent->state_current.effects & 0xFF00) | MSG_ReadByte();
-       if (bits & U_ORIGIN1)   ent->state_current.origin[0] = MSG_ReadCoord();
-       if (bits & U_ANGLE1)    ent->state_current.angles[0] = MSG_ReadAngle();
-       if (bits & U_ORIGIN2)   ent->state_current.origin[1] = MSG_ReadCoord();
-       if (bits & U_ANGLE2)    ent->state_current.angles[1] = MSG_ReadAngle();
-       if (bits & U_ORIGIN3)   ent->state_current.origin[2] = MSG_ReadCoord();
-       if (bits & U_ANGLE3)    ent->state_current.angles[2] = MSG_ReadAngle();
-       if (bits & U_STEP)              ent->state_current.flags |= RENDER_STEP;
-       if (bits & U_ALPHA)             ent->state_current.alpha = MSG_ReadByte();
-       if (bits & U_SCALE)             ent->state_current.scale = MSG_ReadByte();
-       if (bits & U_EFFECTS2)  ent->state_current.effects = (ent->state_current.effects & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_GLOWSIZE)  ent->state_current.glowsize = MSG_ReadByte();
-       if (bits & U_GLOWCOLOR) ent->state_current.glowcolor = MSG_ReadByte();
-       if (bits & U_GLOWTRAIL) ent->state_current.flags |= RENDER_GLOWTRAIL;
-       if (bits & U_COLORMOD)  ent->state_current.colormod = MSG_ReadByte();
-       if (bits & U_FRAME2)    ent->state_current.frame = (ent->state_current.frame & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_MODEL2)    ent->state_current.modelindex = (ent->state_current.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_VIEWMODEL) ent->state_current.flags |= RENDER_VIEWMODEL;
-       if (bits & U_EXTERIORMODEL)     ent->state_current.flags |= RENDER_EXTERIORMODEL;
+               new = ent->state_baseline;
+
+       new.time = cl.mtime[0];
+
+       new.flags = 0;
+       new.active = true;
+       if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
+       if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
+       if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
+       if (bits & U_SKIN)              new.skin = MSG_ReadByte();
+       if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
+       if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
+       if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
+       if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
+       if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
+       if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
+       if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
+       if (bits & U_STEP)              new.flags |= RENDER_STEP;
+       if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
+       if (bits & U_SCALE)             new.scale = MSG_ReadByte();
+       if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
+       if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
+#if 0
+       if (bits & U_COLORMOD)  {int i = MSG_ReadByte();float r = (((int) i >> 5) & 7) * 1.0 / 7, g = (((int) i >> 2) & 7) * 1.0 / 7, b = ((int) i & 3) * 1.0 / 3;Con_Printf("warning: U_COLORMOD %i (%1.2f %1.2f %1.2f) ignored\n", i, r, g, b);}
+#else
+       // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
+       if (bits & U_COLORMOD)  MSG_ReadByte();
+#endif
+       if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
+       if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
+       if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
+       if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
 
        // LordHavoc: to allow playback of the Nehahra movie
        if (Nehahrademcompatibility && (bits & U_EXTEND1))
 
        // LordHavoc: to allow playback of the Nehahra movie
        if (Nehahrademcompatibility && (bits & U_EXTEND1))
@@ -892,44 +913,42 @@ void CL_ParseUpdate (int bits)
                if (i == 2)
                {
                        if (MSG_ReadFloat())
                if (i == 2)
                {
                        if (MSG_ReadFloat())
-                               ent->state_current.effects |= EF_FULLBRIGHT;
+                               new.effects |= EF_FULLBRIGHT;
                }
                if (j < 0)
                }
                if (j < 0)
-                       ent->state_current.alpha = 0;
+                       new.alpha = 0;
                else if (j == 0 || j >= 255)
                else if (j == 0 || j >= 255)
-                       ent->state_current.alpha = 255;
+                       new.alpha = 255;
                else
                else
-                       ent->state_current.alpha = j;
+                       new.alpha = j;
        }
 
        if (deltadie)
        {
                // hide the entity
        }
 
        if (deltadie)
        {
                // hide the entity
-               ent->state_current.active = false;
+               new.active = false;
        }
        else
        }
        else
-       {
-               CL_ValidateState(&ent->state_current);
+               CL_ValidateState(&new);
 
 
-               /*
-               if (!ent->state_current.active)
+       if (new.flags & RENDER_STEP) // FIXME: rename this flag?
+       {
+               // make time identical for memcmp
+               new.time = ent->state_current.time;
+               if (memcmp(&new, &ent->state_current, sizeof(entity_state_t)))
                {
                {
-                       if (bits & U_DELTA)
-                       {
-                               if (bits & U_MODEL)
-                                       Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i %i\n", num, ent->state_previous.modelindex, ent->state_current.modelindex);
-                               else
-                                       Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i\n", num, ent->state_previous.modelindex);
-                       }
-                       else
-                       {
-                               if (bits & U_MODEL)
-                                       Con_Printf("CL_ParseUpdate:       NULL model on %i: %i %i\n", num, ent->state_baseline.modelindex, ent->state_current.modelindex);
-                               else
-                                       Con_Printf("CL_ParseUpdate:       NULL model on %i: %i\n", num, ent->state_baseline.modelindex);
-                       }
+                       // state has changed
+                       ent->state_previous = ent->state_current;
+                       ent->state_current = new;
+                       // assume 10fps animation
+                       ent->state_previous.time = cl.mtime[0];
+                       ent->state_current.time = cl.mtime[0] + 0.1; //ent->state_previous.time + 0.1;
                }
                }
-               */
+       }
+       else
+       {
+               ent->state_previous = ent->state_current;
+               ent->state_current = new;
        }
 }
 
        }
 }
 
@@ -957,7 +976,7 @@ char *bitprofilenames[32] =
        "U_EFFECTS2",
        "U_GLOWSIZE",
        "U_GLOWCOLOR",
        "U_EFFECTS2",
        "U_GLOWSIZE",
        "U_GLOWCOLOR",
-       "U_COLORMOD",
+       "obsolete U_COLORMOD",
        "U_EXTEND2",
        "U_GLOWTRAIL",
        "U_VIEWMODEL",
        "U_EXTEND2",
        "U_GLOWTRAIL",
        "U_VIEWMODEL",
@@ -1028,7 +1047,6 @@ void CL_ParseBaseline (entity_t *ent, int large)
        ent->state_baseline.scale = 16;
        ent->state_baseline.glowsize = 0;
        ent->state_baseline.glowcolor = 254;
        ent->state_baseline.scale = 16;
        ent->state_baseline.glowsize = 0;
        ent->state_baseline.glowcolor = 254;
-       ent->state_baseline.colormod = 255;
        ent->state_previous = ent->state_current = ent->state_baseline;
 
        CL_ValidateState(&ent->state_baseline);
        ent->state_previous = ent->state_current = ent->state_baseline;
 
        CL_ValidateState(&ent->state_baseline);
@@ -1141,7 +1159,6 @@ void CL_ParseStatic (int large)
        ent->render.alpha = 1;
        ent->render.scale = 1;
        ent->render.alpha = 1;
        ent->render.alpha = 1;
        ent->render.scale = 1;
        ent->render.alpha = 1;
-       ent->render.colormod[0] = ent->render.colormod[1] = ent->render.colormod[2] = 1;
 
        VectorCopy (ent->state_baseline.origin, ent->render.origin);
        VectorCopy (ent->state_baseline.angles, ent->render.angles);    
 
        VectorCopy (ent->state_baseline.origin, ent->render.origin);
        VectorCopy (ent->state_baseline.angles, ent->render.angles);    
@@ -1197,7 +1214,7 @@ void CL_ParseEffect2 (void)
 }
 
 
 }
 
 
-#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
+#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
 
 /*
 =====================
 
 /*
 =====================
@@ -1215,9 +1232,9 @@ void CL_ParseServerMessage (void)
 //
 // if recording demos, copy the message out
 //
 //
 // if recording demos, copy the message out
 //
-       if (cl_shownet.value == 1)
+       if (cl_shownet.integer == 1)
                Con_Printf ("%i ",net_message.cursize);
                Con_Printf ("%i ",net_message.cursize);
-       else if (cl_shownet.value == 2)
+       else if (cl_shownet.integer == 2)
                Con_Printf ("------------------\n");
        
        cl.onground = false;    // unless the server says otherwise     
                Con_Printf ("------------------\n");
        
        cl.onground = false;    // unless the server says otherwise     
@@ -1303,7 +1320,7 @@ void CL_ParseServerMessage (void)
                        cl.mtime[1] = cl.mtime[0];
                        cl.mtime[0] = MSG_ReadFloat ();                 
                        break;
                        cl.mtime[1] = cl.mtime[0];
                        cl.mtime[0] = MSG_ReadFloat ();                 
                        break;
-                       
+
                case svc_clientdata:
                        i = MSG_ReadShort ();
                        CL_ParseClientdata (i);
                case svc_clientdata:
                        i = MSG_ReadShort ();
                        CL_ParseClientdata (i);
@@ -1316,7 +1333,7 @@ void CL_ParseServerMessage (void)
                        Nehahrademcompatibility = false;
                        if (i == 250)
                                Nehahrademcompatibility = true;
                        Nehahrademcompatibility = false;
                        if (i == 250)
                                Nehahrademcompatibility = true;
-                       if (cls.demoplayback && demo_nehahra.value)
+                       if (cls.demoplayback && demo_nehahra.integer)
                                Nehahrademcompatibility = true;
                        dpprotocol = i == DPPROTOCOL_VERSION;
                        break;
                                Nehahrademcompatibility = true;
                        dpprotocol = i == DPPROTOCOL_VERSION;
                        break;
@@ -1335,11 +1352,11 @@ void CL_ParseServerMessage (void)
                case svc_stufftext:
                        Cbuf_AddText (MSG_ReadString ());
                        break;
                case svc_stufftext:
                        Cbuf_AddText (MSG_ReadString ());
                        break;
-                       
+
                case svc_damage:
                        V_ParseDamage ();
                        break;
                case svc_damage:
                        V_ParseDamage ();
                        break;
-                       
+
                case svc_serverinfo:
                        CL_ParseServerInfo ();
 //                     vid.recalc_refdef = true;       // leave intermission full screen
                case svc_serverinfo:
                        CL_ParseServerInfo ();
 //                     vid.recalc_refdef = true;       // leave intermission full screen
@@ -1375,7 +1392,7 @@ void CL_ParseServerMessage (void)
                        i = MSG_ReadShort();
                        S_StopSound(i>>3, i&7);
                        break;
                        i = MSG_ReadShort();
                        S_StopSound(i>>3, i&7);
                        break;
-               
+
                case svc_updatename:
                        i = MSG_ReadByte ();
                        if (i >= cl.maxclients)
                case svc_updatename:
                        i = MSG_ReadByte ();
                        if (i >= cl.maxclients)
@@ -1398,7 +1415,7 @@ void CL_ParseServerMessage (void)
                        break;
                        
                case svc_particle:
                        break;
                        
                case svc_particle:
-                       R_ParseParticleEffect ();
+                       CL_ParseParticleEffect ();
                        break;
 
                case svc_effect:
                        break;
 
                case svc_effect:
@@ -1487,7 +1504,7 @@ void CL_ParseServerMessage (void)
                        cl.intermission = 2;
                        cl.completed_time = cl.time;
 //                     vid.recalc_refdef = true;       // go to full screen
                        cl.intermission = 2;
                        cl.completed_time = cl.time;
 //                     vid.recalc_refdef = true;       // go to full screen
-                       SCR_CenterPrint (MSG_ReadString ());                    
+                       SCR_CenterPrint (MSG_ReadString ());
                        break;
 
                case svc_cutscene:
                        break;
 
                case svc_cutscene:
diff --git a/cl_particles.c b/cl_particles.c
new file mode 100644 (file)
index 0000000..12fe619
--- /dev/null
@@ -0,0 +1,1181 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+#define MAX_PARTICLES                  16384   // default max # of particles at one time
+#define ABSOLUTE_MIN_PARTICLES 512             // no fewer than this no matter what's on the command line
+
+typedef enum
+{
+       pt_static, pt_grav, pt_blob, pt_blob2, pt_bulletsmoke, pt_smoke, pt_snow, pt_rain, pt_spark, pt_bubble, pt_fade, pt_steam, pt_splash, pt_splashpuff, pt_flame, pt_blood, pt_oneframe, pt_lavasplash, pt_raindropsplash, pt_underwaterspark, pt_explosionsplash
+}
+ptype_t;
+
+typedef struct particle_s
+{
+       ptype_t         type;
+       vec3_t          org;
+       vec3_t          vel;
+       int                     tex;
+       float           die;
+       float           scale;
+       float           alpha; // 0-255
+       float           time2; // used for various things (snow fluttering, for example)
+       float           bounce; // how much bounce-back from a surface the particle hits (0 = no physics, 1 = stop and slide, 2 = keep bouncing forever, 1.5 is typical)
+       vec3_t          oldorg;
+       vec3_t          vel2; // used for snow fluttering (base velocity, wind for instance)
+       float           friction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction)
+       float           pressure; // if non-zero, apply pressure to other particles
+       int                     dynlight; // if set the particle will be dynamically lit (if cl_dynamicparticles is on), used for smoke and blood
+       byte            color[4];
+}
+particle_t;
+
+static int particlepalette[256] =
+{
+       0x000000,0x0f0f0f,0x1f1f1f,0x2f2f2f,0x3f3f3f,0x4b4b4b,0x5b5b5b,0x6b6b6b,
+       0x7b7b7b,0x8b8b8b,0x9b9b9b,0xababab,0xbbbbbb,0xcbcbcb,0xdbdbdb,0xebebeb,
+       0x0f0b07,0x170f0b,0x1f170b,0x271b0f,0x2f2313,0x372b17,0x3f2f17,0x4b371b,
+       0x533b1b,0x5b431f,0x634b1f,0x6b531f,0x73571f,0x7b5f23,0x836723,0x8f6f23,
+       0x0b0b0f,0x13131b,0x1b1b27,0x272733,0x2f2f3f,0x37374b,0x3f3f57,0x474767,
+       0x4f4f73,0x5b5b7f,0x63638b,0x6b6b97,0x7373a3,0x7b7baf,0x8383bb,0x8b8bcb,
+       0x000000,0x070700,0x0b0b00,0x131300,0x1b1b00,0x232300,0x2b2b07,0x2f2f07,
+       0x373707,0x3f3f07,0x474707,0x4b4b0b,0x53530b,0x5b5b0b,0x63630b,0x6b6b0f,
+       0x070000,0x0f0000,0x170000,0x1f0000,0x270000,0x2f0000,0x370000,0x3f0000,
+       0x470000,0x4f0000,0x570000,0x5f0000,0x670000,0x6f0000,0x770000,0x7f0000,
+       0x131300,0x1b1b00,0x232300,0x2f2b00,0x372f00,0x433700,0x4b3b07,0x574307,
+       0x5f4707,0x6b4b0b,0x77530f,0x835713,0x8b5b13,0x975f1b,0xa3631f,0xaf6723,
+       0x231307,0x2f170b,0x3b1f0f,0x4b2313,0x572b17,0x632f1f,0x733723,0x7f3b2b,
+       0x8f4333,0x9f4f33,0xaf632f,0xbf772f,0xcf8f2b,0xdfab27,0xefcb1f,0xfff31b,
+       0x0b0700,0x1b1300,0x2b230f,0x372b13,0x47331b,0x533723,0x633f2b,0x6f4733,
+       0x7f533f,0x8b5f47,0x9b6b53,0xa77b5f,0xb7876b,0xc3937b,0xd3a38b,0xe3b397,
+       0xab8ba3,0x9f7f97,0x937387,0x8b677b,0x7f5b6f,0x775363,0x6b4b57,0x5f3f4b,
+       0x573743,0x4b2f37,0x43272f,0x371f23,0x2b171b,0x231313,0x170b0b,0x0f0707,
+       0xbb739f,0xaf6b8f,0xa35f83,0x975777,0x8b4f6b,0x7f4b5f,0x734353,0x6b3b4b,
+       0x5f333f,0x532b37,0x47232b,0x3b1f23,0x2f171b,0x231313,0x170b0b,0x0f0707,
+       0xdbc3bb,0xcbb3a7,0xbfa39b,0xaf978b,0xa3877b,0x977b6f,0x876f5f,0x7b6353,
+       0x6b5747,0x5f4b3b,0x533f33,0x433327,0x372b1f,0x271f17,0x1b130f,0x0f0b07,
+       0x6f837b,0x677b6f,0x5f7367,0x576b5f,0x4f6357,0x475b4f,0x3f5347,0x374b3f,
+       0x2f4337,0x2b3b2f,0x233327,0x1f2b1f,0x172317,0x0f1b13,0x0b130b,0x070b07,
+       0xfff31b,0xefdf17,0xdbcb13,0xcbb70f,0xbba70f,0xab970b,0x9b8307,0x8b7307,
+       0x7b6307,0x6b5300,0x5b4700,0x4b3700,0x3b2b00,0x2b1f00,0x1b0f00,0x0b0700,
+       0x0000ff,0x0b0bef,0x1313df,0x1b1bcf,0x2323bf,0x2b2baf,0x2f2f9f,0x2f2f8f,
+       0x2f2f7f,0x2f2f6f,0x2f2f5f,0x2b2b4f,0x23233f,0x1b1b2f,0x13131f,0x0b0b0f,
+       0x2b0000,0x3b0000,0x4b0700,0x5f0700,0x6f0f00,0x7f1707,0x931f07,0xa3270b,
+       0xb7330f,0xc34b1b,0xcf632b,0xdb7f3b,0xe3974f,0xe7ab5f,0xefbf77,0xf7d38b,
+       0xa77b3b,0xb79b37,0xc7c337,0xe7e357,0x7fbfff,0xabe7ff,0xd7ffff,0x670000,
+       0x8b0000,0xb30000,0xd70000,0xff0000,0xfff393,0xfff7c7,0xffffff,0x9f5b53
+};
+
+static int explosparkramp[8] = {0x4b0700, 0x6f0f00, 0x931f07, 0xb7330f, 0xcf632b, 0xe3974f, 0xffe7b5, 0xffffff};
+//static int explounderwatersparkramp[8] = {0x00074b, 0x000f6f, 0x071f93, 0x0f33b7, 0x2b63cf, 0x4f97e3, 0xb5e7ff, 0xffffff};
+
+// these must match r_part.c's textures
+static const int tex_smoke[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+static const int tex_bullethole[8] = {8, 9, 10, 11, 12, 13, 14, 15};
+static const int tex_rainsplash[16] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
+static const int tex_particle = 32;
+static const int tex_rain = 33;
+static const int tex_bubble = 34;
+static const int tex_rocketglow = 35;
+
+static int                     cl_maxparticles;
+static int                     cl_numparticles;
+static particle_t      *particles;
+static particle_t      **freeparticles; // list used only in compacting particles array
+static renderparticle_t        *cl_renderparticles;
+
+static cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1"};
+static cvar_t cl_particles_size = {CVAR_SAVE, "cl_particles_size", "1"};
+static cvar_t cl_particles_bloodshowers = {CVAR_SAVE, "cl_particles_bloodshowers", "1"};
+static cvar_t cl_particles_blood = {CVAR_SAVE, "cl_particles_blood", "1"};
+static cvar_t cl_particles_smoke = {CVAR_SAVE, "cl_particles_smoke", "1"};
+static cvar_t cl_particles_sparks = {CVAR_SAVE, "cl_particles_sparks", "1"};
+static cvar_t cl_particles_bubbles = {CVAR_SAVE, "cl_particles_bubbles", "1"};
+static cvar_t cl_particles_explosions = {CVAR_SAVE, "cl_particles_explosions", "0"};
+
+static mempool_t *cl_part_mempool;
+
+void CL_Particles_Clear(void)
+{
+       cl_numparticles = 0;
+}
+
+/*
+===============
+CL_InitParticles
+===============
+*/
+void CL_ReadPointFile_f (void);
+void CL_Particles_Init (void)
+{
+       int             i;
+
+       i = COM_CheckParm ("-particles");
+
+       if (i)
+       {
+               cl_maxparticles = (int)(atoi(com_argv[i+1]));
+               if (cl_maxparticles < ABSOLUTE_MIN_PARTICLES)
+                       cl_maxparticles = ABSOLUTE_MIN_PARTICLES;
+       }
+       else
+               cl_maxparticles = MAX_PARTICLES;
+
+       Cmd_AddCommand ("pointfile", CL_ReadPointFile_f);
+
+       Cvar_RegisterVariable (&cl_particles);
+       Cvar_RegisterVariable (&cl_particles_size);
+       Cvar_RegisterVariable (&cl_particles_bloodshowers);
+       Cvar_RegisterVariable (&cl_particles_blood);
+       Cvar_RegisterVariable (&cl_particles_smoke);
+       Cvar_RegisterVariable (&cl_particles_sparks);
+       Cvar_RegisterVariable (&cl_particles_bubbles);
+       Cvar_RegisterVariable (&cl_particles_explosions);
+
+       cl_part_mempool = Mem_AllocPool("CL_Part");
+       particles = (particle_t *) Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(particle_t));
+       freeparticles = (void *) Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(particle_t *));
+       cl_numparticles = 0;
+
+       // FIXME: r_refdef stuff should be allocated somewhere else?
+       r_refdef.particles = cl_renderparticles = Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(renderparticle_t));
+}
+
+#define particle(ptype, pcolor, ptex, plight, pscale, palpha, ptime, pbounce, px, py, pz, pvx, pvy, pvz, ptime2, pvx2, pvy2, pvz2, pfriction, ppressure)\
+{\
+       particle_t      *part;\
+       int tempcolor;\
+       if (cl_numparticles >= cl_maxparticles)\
+               return;\
+       part = &particles[cl_numparticles++];\
+       part->type = (ptype);\
+       tempcolor = (pcolor);\
+       part->color[0] = ((tempcolor) >> 16) & 0xFF;\
+       part->color[1] = ((tempcolor) >> 8) & 0xFF;\
+       part->color[2] = (tempcolor) & 0xFF;\
+       part->color[3] = 0xFF;\
+       part->tex = (ptex);\
+       part->dynlight = (plight);\
+       part->scale = (pscale);\
+       part->alpha = (palpha);\
+       part->die = cl.time + (ptime);\
+       part->bounce = (pbounce);\
+       part->org[0] = (px);\
+       part->org[1] = (py);\
+       part->org[2] = (pz);\
+       part->vel[0] = (pvx);\
+       part->vel[1] = (pvy);\
+       part->vel[2] = (pvz);\
+       part->time2 = (ptime2);\
+       part->vel2[0] = (pvx2);\
+       part->vel2[1] = (pvy2);\
+       part->vel2[2] = (pvz2);\
+       part->friction = (pfriction);\
+       part->pressure = (ppressure);\
+}
+
+/*
+===============
+CL_EntityParticles
+===============
+*/
+void CL_EntityParticles (entity_t *ent)
+{
+       int                     i;
+       float           angle;
+       float           sp, sy, cp, cy;
+       vec3_t          forward;
+       float           dist;
+       float           beamlength;
+       static vec3_t avelocities[NUMVERTEXNORMALS];
+       if (!cl_particles.integer) return;
+
+       dist = 64;
+       beamlength = 16;
+
+       if (!avelocities[0][0])
+               for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+                       avelocities[0][i] = (rand()&255) * 0.01;
+
+       for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+       {
+               angle = cl.time * avelocities[i][0];
+               sy = sin(angle);
+               cy = cos(angle);
+               angle = cl.time * avelocities[i][1];
+               sp = sin(angle);
+               cp = cos(angle);
+
+               forward[0] = cp*cy;
+               forward[1] = cp*sy;
+               forward[2] = -sp;
+
+               particle(pt_oneframe, particlepalette[0x6f], tex_particle, false, 2, 255, 9999, 0, ent->render.origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->render.origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->render.origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+       }
+}
+
+
+void CL_ReadPointFile_f (void)
+{
+       vec3_t  org;
+       int             r, c;
+       char    *pointfile, *pointfilepos, *t, tchar;
+
+       pointfile = COM_LoadFile(va("maps/%s.pts", sv.name), true);
+       if (!pointfile)
+       {
+               Con_Printf ("couldn't open %s.pts\n", sv.name);
+               return;
+       }
+
+       Con_Printf ("Reading %s.pts...\n", sv.name);
+       c = 0;
+       pointfilepos = pointfile;
+       while (*pointfilepos)
+       {
+               while (*pointfilepos == '\n' || *pointfilepos == '\r')
+                       pointfilepos++;
+               if (!*pointfilepos)
+                       break;
+               t = pointfilepos;
+               while (*t && *t != '\n' && *t != '\r')
+                       t++;
+               tchar = *t;
+               *t = 0;
+               r = sscanf (pointfilepos,"%f %f %f", &org[0], &org[1], &org[2]);
+               *t = tchar;
+               pointfilepos = t;
+               if (r != 3)
+                       break;
+               c++;
+
+               if (cl_numparticles >= cl_maxparticles)
+               {
+                       Con_Printf ("Not enough free particles\n");
+                       break;
+               }
+               particle(pt_static, particlepalette[(-c)&15], tex_particle, false, 2, 255, 99999, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+       }
+
+       Mem_Free(pointfile);
+       Con_Printf ("%i points read\n", c);
+}
+
+/*
+===============
+CL_ParseParticleEffect
+
+Parse an effect out of the server message
+===============
+*/
+void CL_ParseParticleEffect (void)
+{
+       vec3_t          org, dir;
+       int                     i, count, msgcount, color;
+
+       for (i=0 ; i<3 ; i++)
+               org[i] = MSG_ReadCoord ();
+       for (i=0 ; i<3 ; i++)
+               dir[i] = MSG_ReadChar () * (1.0/16);
+       msgcount = MSG_ReadByte ();
+       color = MSG_ReadByte ();
+
+       if (msgcount == 255)
+               count = 1024;
+       else
+               count = msgcount;
+
+       CL_RunParticleEffect (org, dir, color, count);
+}
+
+/*
+===============
+CL_ParticleExplosion
+
+===============
+*/
+void CL_ParticleExplosion (vec3_t org, int smoke)
+{
+       int i, j;
+       float f;
+       vec3_t v, end, ang;
+       byte noise1[32*32], noise2[32*32];
+
+       if (cl_particles.integer && cl_particles_explosions.integer)
+       {
+               i = Mod_PointInLeaf(org, cl.worldmodel)->contents;
+               if (i == CONTENTS_SLIME || i == CONTENTS_WATER)
+               {
+                       for (i = 0;i < 128;i++)
+                               particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-96, 96), lhrandom(-96, 96), lhrandom(-96, 96), 0, 0, 0, 0, 0, 0);
+
+                       ang[2] = lhrandom(0, 360);
+                       fractalnoise(noise1, 32, 4);
+                       fractalnoise(noise2, 32, 8);
+                       for (i = 0;i < 32;i++)
+                       {
+                               for (j = 0;j < 32;j++)
+                               {
+                                       VectorRandom(v);
+                                       VectorMA(org, 16, v, v);
+                                       TraceLine(org, v, end, NULL, 0);
+                                       ang[0] = (j + 0.5f) * (360.0f / 32.0f);
+                                       ang[1] = (i + 0.5f) * (360.0f / 32.0f);
+                                       AngleVectors(ang, v, NULL, NULL);
+                                       f = noise1[j*32+i] * 1.5f;
+                                       VectorScale(v, f, v);
+                                       particle(pt_underwaterspark, noise2[j*32+i] * 0x010101, tex_smoke[rand()&7], false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0);
+                                       VectorScale(v, 0.75, v);
+                                       particle(pt_underwaterspark, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0);
+                               }
+                       }
+               }
+               else
+               {
+                       ang[2] = lhrandom(0, 360);
+                       fractalnoise(noise1, 32, 4);
+                       fractalnoise(noise2, 32, 8);
+                       for (i = 0;i < 32;i++)
+                       {
+                               for (j = 0;j < 32;j++)
+                               {
+                                       VectorRandom(v);
+                                       VectorMA(org, 16, v, v);
+                                       TraceLine(org, v, end, NULL, 0);
+                                       ang[0] = (j + 0.5f) * (360.0f / 32.0f);
+                                       ang[1] = (i + 0.5f) * (360.0f / 32.0f);
+                                       AngleVectors(ang, v, NULL, NULL);
+                                       f = noise1[j*32+i] * 1.5f;
+                                       VectorScale(v, f, v);
+                                       particle(pt_spark, noise2[j*32+i] * 0x010101, tex_smoke[random()&7], false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+                                       VectorScale(v, 0.75, v);
+                                       particle(pt_spark, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+                               //      VectorRandom(v);
+                               //      VectorScale(v, 384, v);
+                               //      particle(pt_spark, explosparkramp[rand()&7], tex_particle, false, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+                               }
+                       }
+               }
+       }
+       else
+       {
+               R_NewExplosion(org);
+
+               for (i = 0;i < 256;i++)
+               {
+                       VectorRandom(v);
+                       particle(pt_spark, explosparkramp[rand()&7], tex_particle, false, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0] * 384.0f, v[1] * 384.0f, v[2] * 384.0f + 160.0f, 512.0f, 0, 0, 0, 2, 0);
+               }
+       }
+}
+
+/*
+===============
+CL_ParticleExplosion2
+
+===============
+*/
+void CL_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
+{
+       int                     i;
+       if (!cl_particles.integer) return;
+
+       for (i = 0;i < 512;i++)
+               particle(pt_fade, particlepalette[colorStart + (i % colorLength)], tex_particle, false, 1.5, 255, 0.3, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192), 0, 0, 0, 0, 0.1f, 0);
+}
+
+/*
+===============
+CL_BlobExplosion
+
+===============
+*/
+void CL_BlobExplosion (vec3_t org)
+{
+       int                     i;
+       if (!cl_particles.integer) return;
+
+       for (i = 0;i < 256;i++)
+               particle(pt_blob , particlepalette[ 66+(rand()%6)], tex_particle, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0);
+       for (i = 0;i < 256;i++)
+               particle(pt_blob2, particlepalette[150+(rand()%6)], tex_particle, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0);
+}
+
+/*
+===============
+CL_RunParticleEffect
+
+===============
+*/
+void CL_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
+{
+       if (!cl_particles.integer) return;
+
+       if (count == 1024)
+       {
+               CL_ParticleExplosion(org, false);
+               return;
+       }
+       while (count--)
+               particle(pt_fade, particlepalette[color + (rand()&7)], tex_particle, false, 1, 128, 9999, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-15, 15), lhrandom(-15, 15), lhrandom(-15, 15), 0, 0, 0, 0, 0, 0);
+}
+
+// LordHavoc: added this for spawning sparks/dust (which have strong gravity)
+/*
+===============
+CL_SparkShower
+===============
+*/
+void CL_SparkShower (vec3_t org, vec3_t dir, int count)
+{
+       if (!cl_particles.integer) return;
+
+       CL_Decal(org, tex_bullethole[rand()&7], 16 * cl_particles_size.value, 0, 0, 0, 1);
+
+       // smoke puff
+       if (cl_particles_smoke.integer)
+               particle(pt_bulletsmoke, 0xA0A0A0, tex_smoke[rand()&7], true, 5, 255, 9999, 0, org[0], org[1], org[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 0, 0, 0, 0, 0, 0);
+
+       if (cl_particles_sparks.integer)
+       {
+               // sparks
+               while(count--)
+                       particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(0, 255), 9999, 1.5, org[0], org[1], org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(0, 128), 512.0f, 0, 0, 0, 0.2f, 0);
+       }
+}
+
+void CL_BloodPuff (vec3_t org, vec3_t vel, int count)
+{
+       // bloodcount is used to accumulate counts too small to cause a blood particle
+       static int bloodcount = 0;
+       if (!cl_particles.integer) return;
+       if (!cl_particles_blood.integer) return;
+
+       if (count > 100)
+               count = 100;
+       bloodcount += count;
+       while(bloodcount >= 10)
+       {
+               particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
+               bloodcount -= 10;
+       }
+}
+
+void CL_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
+{
+       vec3_t diff, center, velscale;
+       if (!cl_particles.integer) return;
+       if (!cl_particles_bloodshowers.integer) return;
+       if (!cl_particles_blood.integer) return;
+
+       VectorSubtract(maxs, mins, diff);
+       center[0] = (mins[0] + maxs[0]) * 0.5;
+       center[1] = (mins[1] + maxs[1]) * 0.5;
+       center[2] = (mins[2] + maxs[2]) * 0.5;
+       // FIXME: change velspeed back to 2.0x after fixing mod
+       velscale[0] = velspeed * 2.0 / diff[0];
+       velscale[1] = velspeed * 2.0 / diff[1];
+       velscale[2] = velspeed * 2.0 / diff[2];
+
+       while (count--)
+       {
+               vec3_t org, vel;
+               org[0] = lhrandom(mins[0], maxs[0]);
+               org[1] = lhrandom(mins[1], maxs[1]);
+               org[2] = lhrandom(mins[2], maxs[2]);
+               vel[0] = (org[0] - center[0]) * velscale[0];
+               vel[1] = (org[1] - center[1]) * velscale[1];
+               vel[2] = (org[2] - center[2]) * velscale[2];
+               particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0], vel[1], vel[2], 0, 0, 0, 0, 1.0f, 0);
+       }
+}
+
+void CL_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel)
+{
+       float           t;
+       if (!cl_particles.integer) return;
+       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
+       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
+       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
+
+       while (count--)
+               particle(gravity ? pt_grav : pt_static, particlepalette[colorbase + (rand()&3)], tex_particle, false, 2, 255, lhrandom(1, 2), 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0] + lhrandom(-randomvel, randomvel), dir[1] + lhrandom(-randomvel, randomvel), dir[2] + lhrandom(-randomvel, randomvel), 0, 0, 0, 0, 0, 0);
+}
+
+void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type)
+{
+       vec3_t          vel;
+       float           t, z;
+       if (!cl_particles.integer) return;
+       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
+       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
+       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
+       if (dir[2] < 0) // falling
+       {
+               t = (maxs[2] - mins[2]) / -dir[2];
+               z = maxs[2];
+       }
+       else // rising??
+       {
+               t = (maxs[2] - mins[2]) / dir[2];
+               z = mins[2];
+       }
+       if (t < 0 || t > 2) // sanity check
+               t = 2;
+
+       switch(type)
+       {
+       case 0:
+               while(count--)
+               {
+                       vel[0] = dir[0] + lhrandom(-16, 16);
+                       vel[1] = dir[1] + lhrandom(-16, 16);
+                       vel[2] = dir[2] + lhrandom(-32, 32);
+                       particle(pt_rain, particlepalette[colorbase + (rand()&3)], tex_rain, true, 3, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0);
+               }
+               break;
+       case 1:
+               while(count--)
+               {
+                       vel[0] = dir[0] + lhrandom(-16, 16);
+                       vel[1] = dir[1] + lhrandom(-16, 16);
+                       vel[2] = dir[2] + lhrandom(-32, 32);
+                       particle(pt_snow, particlepalette[colorbase + (rand()&3)], tex_particle, false, 2, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0);
+               }
+               break;
+       default:
+               Host_Error("CL_ParticleRain: unknown type %i (0 = rain, 1 = snow)\n", type);
+       }
+}
+
+void CL_FlameCube (vec3_t mins, vec3_t maxs, int count)
+{
+       float           t;
+       if (!cl_particles.integer) return;
+       if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
+       if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
+       if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
+
+       while (count--)
+               particle(pt_flame, particlepalette[224 + (rand()&15)], tex_particle, false, 8, 255, 9999, 1.1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), lhrandom(-32, 32), lhrandom(-32, 32), lhrandom(-32, 64), 0, 0, 0, 0, 0.1f, 0);
+}
+
+void CL_Flames (vec3_t org, vec3_t vel, int count)
+{
+       if (!cl_particles.integer) return;
+
+       while (count--)
+               particle(pt_flame, particlepalette[224 + (rand()&15)], tex_particle, false, 8, 255, 9999, 1.1, org[0], org[1], org[2], vel[0] + lhrandom(-128, 128), vel[1] + lhrandom(-128, 128), vel[2] + lhrandom(-128, 128), 0, 0, 0, 0, 0.1f, 0);
+}
+
+
+
+/*
+===============
+CL_LavaSplash
+
+===============
+*/
+void CL_LavaSplash (vec3_t origin)
+{
+       int                     i, j;
+       float           vel;
+       vec3_t          dir, org;
+       if (!cl_particles.integer) return;
+
+       for (i=-128 ; i<128 ; i+=16)
+       {
+               for (j=-128 ; j<128 ; j+=16)
+               {
+                       dir[0] = j + lhrandom(0, 8);
+                       dir[1] = i + lhrandom(0, 8);
+                       dir[2] = 256;
+                       org[0] = origin[0] + dir[0];
+                       org[1] = origin[1] + dir[1];
+                       org[2] = origin[2] + lhrandom(0, 64);
+                       vel = lhrandom(50, 120) / VectorLength(dir); // normalize and scale
+                       particle(pt_lavasplash, particlepalette[224 + (rand()&7)], tex_particle, false, 7, 255, 9999, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, 0, 0);
+               }
+       }
+}
+
+/*
+===============
+CL_TeleportSplash
+
+===============
+*/
+void CL_TeleportSplash (vec3_t org)
+{
+       int                     i, j, k;
+       if (!cl_particles.integer) return;
+
+       for (i=-16 ; i<16 ; i+=8)
+               for (j=-16 ; j<16 ; j+=8)
+                       for (k=-24 ; k<32 ; k+=8)
+                               particle(pt_fade, 0xFFFFFF, tex_particle, false, 1, lhrandom(64, 128), 9999, 0, org[0] + i + lhrandom(0, 8), org[1] + j + lhrandom(0, 8), org[2] + k + lhrandom(0, 8), i*2 + lhrandom(-12.5, 12.5), j*2 + lhrandom(-12.5, 12.5), k*2 + lhrandom(27.5, 52.5), 0, 0, 0, 0, 0.1f, -512.0f);
+}
+
+void CL_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
+{
+       vec3_t          vec, dir, vel;
+       float           len, dec = 0, speed;
+       int                     contents, bubbles;
+       double          t;
+       if (!cl_particles.integer) return;
+
+       VectorSubtract(end, start, dir);
+       VectorNormalize(dir);
+
+       if (type == 0 && host_frametime != 0) // rocket glow
+               particle(pt_oneframe, 0xFFFFFF, tex_rocketglow, false, 24, 255, 9999, 0, end[0] - 12 * dir[0], end[1] - 12 * dir[1], end[2] - 12 * dir[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+       t = ent->persistent.trail_time;
+       if (t >= cl.time)
+               return; // no particles to spawn this frame (sparse trail)
+
+       if (t < cl.oldtime)
+               t = cl.oldtime;
+
+       VectorSubtract (end, start, vec);
+       len = VectorNormalizeLength (vec);
+       if (len <= 0.01f)
+       {
+               // advance the trail time
+               ent->persistent.trail_time = cl.time;
+               return;
+       }
+       speed = len / (cl.time - cl.oldtime);
+       VectorScale(vec, speed, vel);
+
+       // advance into this frame to reach the first puff location
+       dec = t - cl.oldtime;
+       dec *= speed;
+       VectorMA(start, dec, vec, start);
+
+       contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
+       if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
+       {
+               // advance the trail time
+               ent->persistent.trail_time = cl.time;
+               return;
+       }
+
+       bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
+
+       while (t < cl.time)
+       {
+               switch (type)
+               {
+                       case 0: // rocket trail
+                               if (!cl_particles_smoke.integer)
+                                       dec = cl.time - t;
+                               else if (bubbles && cl_particles_bubbles.integer)
+                               {
+                                       dec = 0.005f;
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_smoke, 0xFFFFFF, tex_smoke[rand()&7], false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               else
+                               {
+                                       dec = 0.005f;
+                                       particle(pt_smoke, 0xC0C0C0, tex_smoke[rand()&7], true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                                       //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0);
+                               }
+                               break;
+
+                       case 1: // grenade trail
+                               // FIXME: make it gradually stop smoking
+                               if (!cl_particles_smoke.integer)
+                                       dec = cl.time - t;
+                               else if (bubbles && cl_particles_bubbles.integer)
+                               {
+                                       dec = 0.02f;
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0);
+                                       particle(pt_smoke, 0xFFFFFF, tex_smoke[rand()&7], false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               else
+                               {
+                                       dec = 0.02f;
+                                       particle(pt_smoke, 0x808080, tex_smoke[rand()&7], true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               break;
+
+
+                       case 2: // blood
+                               if (!cl_particles_blood.integer)
+                                       dec = cl.time - t;
+                               else
+                               {
+                                       dec = 0.1f;
+                                       particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
+                               }
+                               break;
+
+                       case 4: // slight blood
+                               if (!cl_particles_blood.integer)
+                                       dec = cl.time - t;
+                               else
+                               {
+                                       dec = 0.15f;
+                                       particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0);
+                               }
+                               break;
+
+                       case 3: // green tracer
+                               dec = 0.02f;
+                               particle(pt_fade, 0x373707, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               break;
+
+                       case 5: // flame tracer
+                               dec = 0.02f;
+                               particle(pt_fade, 0xCF632B, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               break;
+
+                       case 6: // voor trail
+                               dec = 0.05f; // sparse trail
+                               particle(pt_fade, 0x47232B, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               break;
+
+                       case 7: // Nehahra smoke tracer
+                               if (!cl_particles_smoke.integer)
+                                       dec = cl.time - t;
+                               else
+                               {
+                                       dec = 0.14f;
+                                       particle(pt_smoke, 0xC0C0C0, tex_smoke[rand()&7], true, 10, 64, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                               }
+                               break;
+               }
+
+               // advance to next time and position
+               t += dec;
+               dec *= speed;
+               VectorMA (start, dec, vec, start);
+       }
+       ent->persistent.trail_time = t;
+}
+
+void CL_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
+{
+       vec3_t          vec;
+       int                     len;
+       if (!cl_particles.integer) return;
+       if (!cl_particles_smoke.integer) return;
+
+       VectorSubtract (end, start, vec);
+       len = (int) (VectorNormalizeLength (vec) * (1.0f / 3.0f));
+       VectorScale(vec, 3, vec);
+       color = particlepalette[color];
+       while (len--)
+       {
+               particle(pt_smoke, color, tex_particle, false, 8, 192, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0);
+               VectorAdd (start, vec, start);
+       }
+}
+
+
+/*
+===============
+CL_MoveParticles
+===============
+*/
+void CL_MoveParticles (void)
+{
+       particle_t *p;
+       renderparticle_t *r;
+       int i, activeparticles, maxparticle, j, a, b, pressureused = false;
+       float gravity, dvel, frametime, f, dist, normal[3], v[3], org[3], o[3];
+
+       // LordHavoc: early out condition
+       if (!cl_numparticles)
+               return;
+
+       frametime = cl.time - cl.oldtime;
+       if (!frametime)
+               return; // if absolutely still, don't update particles
+       gravity = frametime * sv_gravity.value;
+       dvel = 1+4*frametime;
+
+       activeparticles = 0;
+       maxparticle = -1;
+       j = 0;
+       for (i = 0, p = particles, r = r_refdef.particles;i < cl_numparticles;i++, p++)
+       {
+               if (p->die < cl.time)
+               {
+                       freeparticles[j++] = p;
+                       continue;
+               }
+
+               VectorCopy(p->org, p->oldorg);
+               VectorMA(p->org, frametime, p->vel, p->org);
+               if (p->friction)
+               {
+                       f = 1.0f - (p->friction * frametime);
+                       VectorScale(p->vel, f, p->vel);
+               }
+               VectorCopy(p->org, org);
+               if (p->bounce)
+               {
+                       if (TraceLine(p->oldorg, p->org, v, normal, 0) < 1)
+                       {
+                               VectorCopy(v, p->org);
+                               if (p->bounce < 0)
+                               {
+                                       CL_Decal(v, p->tex, p->scale * cl_particles_size.value, p->color[0] * (1.0f / 255.0f), p->color[1] * (1.0f / 255.0f), p->color[2] * (1.0f / 255.0f), p->alpha * (1.0f / 255.0f));
+                                       p->die = -1;
+                                       freeparticles[j++] = p;
+                                       continue;
+                               }
+                               else
+                               {
+                                       dist = DotProduct(p->vel, normal) * -p->bounce;
+                                       VectorMA(p->vel, dist, normal, p->vel);
+                                       if (DotProduct(p->vel, p->vel) < 0.03)
+                                               VectorClear(p->vel);
+                               }
+                       }
+               }
+
+               switch (p->type)
+               {
+               case pt_static:
+                       break;
+
+                       // LordHavoc: drop-through because of shared code
+               case pt_blob:
+                       p->vel[2] *= dvel;
+               case pt_blob2:
+                       p->vel[0] *= dvel;
+                       p->vel[1] *= dvel;
+                       p->alpha -= frametime * 256;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+
+               case pt_grav:
+                       p->vel[2] -= gravity;
+                       break;
+               case pt_lavasplash:
+                       p->vel[2] -= gravity * 0.05;
+                       p->alpha -= frametime * 192;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_snow:
+                       if (cl.time > p->time2)
+                       {
+                               p->time2 = cl.time + (rand() & 3) * 0.1;
+                               p->vel[0] = (rand()&63)-32 + p->vel2[0];
+                               p->vel[1] = (rand()&63)-32 + p->vel2[1];
+                               p->vel[2] = (rand()&63)-32 + p->vel2[2];
+                       }
+                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+                       if (a != CONTENTS_EMPTY && a != CONTENTS_SKY)
+                       {
+                               vec3_t normal;
+                               if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID)
+                                       break; // still in solid
+                               p->die = cl.time + 1000;
+                               p->vel[0] = p->vel[1] = p->vel[2] = 0;
+                               switch (a)
+                               {
+                               case CONTENTS_LAVA:
+                               case CONTENTS_SLIME:
+                                       p->tex = tex_smoke[rand()&7];
+                                       p->type = pt_steam;
+                                       p->alpha = 96;
+                                       p->scale = 5;
+                                       p->vel[2] = 96;
+                                       break;
+                               case CONTENTS_WATER:
+                                       p->tex = tex_smoke[rand()&7];
+                                       p->type = pt_splash;
+                                       p->alpha = 96;
+                                       p->scale = 5;
+                                       p->vel[2] = 96;
+                                       break;
+                               default: // CONTENTS_SOLID and any others
+                                       TraceLine(p->oldorg, p->org, v, normal, 0);
+                                       VectorCopy(v, p->org);
+                                       p->tex = tex_smoke[rand()&7];
+                                       p->type = pt_fade;
+                                       VectorClear(p->vel);
+                                       break;
+                               }
+                       }
+                       break;
+               case pt_blood:
+                       p->friction = 1;
+                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+                       if (a != CONTENTS_EMPTY)
+                       {
+                               if (a == CONTENTS_WATER || a == CONTENTS_SLIME)
+                               {
+                                       p->friction = 5;
+                                       p->scale += frametime * 32.0f;
+                                       p->alpha -= frametime * 128.0f;
+                                       p->vel[2] += gravity * 0.125f;
+                                       if (p->alpha < 1)
+                                               p->die = -1;
+                                       break;
+                               }
+                               else
+                               {
+                                       p->die = -1;
+                                       break;
+                               }
+                       }
+                       p->vel[2] -= gravity * 0.5;
+                       break;
+               case pt_spark:
+                       p->alpha -= frametime * p->time2;
+                       p->vel[2] -= gravity;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       else if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
+                               p->type = pt_underwaterspark;
+                       break;
+               case pt_underwaterspark:
+                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
+                       {
+                               p->tex = tex_smoke[rand()&7];
+                               p->color[0] = p->color[1] = p->color[2] = 255;
+                               p->scale = 16;
+                               p->type = pt_explosionsplash;
+                       }
+                       else
+                               p->vel[2] += gravity * 0.5f;
+                       p->alpha -= frametime * p->time2;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_explosionsplash:
+                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
+                               p->vel[2] -= gravity;
+                       else
+                               p->alpha = 0;
+                       p->scale += frametime * 64.0f;
+                       p->alpha -= frametime * 1024.0f;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_fade:
+                       p->alpha -= frametime * 512;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_bubble:
+                       a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+                       if (a != CONTENTS_WATER && a != CONTENTS_SLIME)
+                       {
+                               p->tex = tex_smoke[rand()&7];
+                               p->type = pt_splashpuff;
+                               p->scale = 4;
+                               p->vel[0] = p->vel[1] = p->vel[2] = 0;
+                               break;
+                       }
+                       p->vel[2] += gravity * 0.25;
+                       p->vel[0] *= (1 - (frametime * 0.0625));
+                       p->vel[1] *= (1 - (frametime * 0.0625));
+                       p->vel[2] *= (1 - (frametime * 0.0625));
+                       if (cl.time > p->time2)
+                       {
+                               p->time2 = cl.time + lhrandom(0, 0.5);
+                               p->vel[0] += lhrandom(-32,32);
+                               p->vel[1] += lhrandom(-32,32);
+                               p->vel[2] += lhrandom(-32,32);
+                       }
+                       p->alpha -= frametime * 256;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_bulletsmoke:
+                       p->scale += frametime * 16;
+                       p->alpha -= frametime * 1024;
+                       p->vel[2] += gravity * 0.1;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_smoke:
+                       p->scale += frametime * 24;
+                       p->alpha -= frametime * 256;
+                       p->vel[2] += gravity * 0.1;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_steam:
+                       p->scale += frametime * 48;
+                       p->alpha -= frametime * 512;
+                       p->vel[2] += gravity * 0.05;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_splashpuff:
+                       p->alpha -= frametime * 1024;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_rain:
+                       f = 0;
+                       b = Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents;
+                       VectorCopy(p->oldorg, o);
+                       while (f < 1)
+                       {
+                               a = b;
+                               f = TraceLine(o, p->org, v, normal, a);
+                               b = traceline_endcontents;
+                               if (f < 1 && b != CONTENTS_EMPTY && b != CONTENTS_SKY)
+                               {
+                                       p->die = cl.time + 1000;
+                                       p->vel[0] = p->vel[1] = p->vel[2] = 0;
+                                       VectorCopy(v, p->org);
+                                       switch (b)
+                                       {
+                                       case CONTENTS_LAVA:
+                                       case CONTENTS_SLIME:
+                                               p->tex = tex_smoke[rand()&7];
+                                               p->type = pt_steam;
+                                               p->scale = 3;
+                                               p->vel[2] = 96;
+                                               break;
+                                       default: // water, solid, and anything else
+                                               p->tex = tex_rainsplash[0];
+                                               p->time2 = 0;
+                                               VectorCopy(normal, p->vel2);
+                                       //      VectorAdd(p->org, normal, p->org);
+                                               p->type = pt_raindropsplash;
+                                               p->scale = 8;
+                                               break;
+                                       }
+                               }
+                       }
+                       break;
+               case pt_raindropsplash:
+                       p->time2 += frametime * 64.0f;
+                       if (p->time2 >= 16.0f)
+                       {
+                               p->die = -1;
+                               break;
+                       }
+                       p->tex = tex_rainsplash[(int) p->time2];
+                       break;
+               case pt_flame:
+                       p->alpha -= frametime * 512;
+                       p->vel[2] += gravity;
+                       if (p->alpha < 16)
+                               p->die = -1;
+                       break;
+               case pt_oneframe:
+                       if (p->time2)
+                               p->die = -1;
+                       p->time2 = 1;
+                       break;
+               default:
+                       printf("unknown particle type %i\n", p->type);
+                       p->die = -1;
+                       break;
+               }
+
+               // LordHavoc: immediate removal of unnecessary particles (must be done to ensure compactor below operates properly in all cases)
+               if (p->die < cl.time)
+                       freeparticles[j++] = p;
+               else
+               {
+                       maxparticle = i;
+                       activeparticles++;
+                       if (p->pressure)
+                               pressureused = true;
+
+                       // build renderparticle for renderer to use
+                       if (p->type == pt_raindropsplash)
+                       {
+                               r->orientation = PARTICLE_ORIENTED_DOUBLESIDED;
+                               r->dir[0] = p->vel2[0];
+                               r->dir[1] = p->vel2[1];
+                               r->dir[2] = p->vel2[2];
+                       }
+                       else if (p->tex == tex_rain)
+                               r->orientation = PARTICLE_UPRIGHT_FACING;
+                       else
+                               r->orientation = PARTICLE_BILLBOARD;
+                       r->org[0] = p->org[0];
+                       r->org[1] = p->org[1];
+                       r->org[2] = p->org[2];
+                       r->tex = p->tex;
+                       r->scale = p->scale * 0.5f * cl_particles_size.value;
+                       r->dynlight = p->dynlight;
+                       r->color[0] = p->color[0] * (1.0f / 255.0f);
+                       r->color[1] = p->color[1] * (1.0f / 255.0f);
+                       r->color[2] = p->color[2] * (1.0f / 255.0f);
+                       r->color[3] = p->alpha * (1.0f / 255.0f);
+                       r++;
+               }
+       }
+       r_refdef.numparticles = r - r_refdef.particles;
+       // fill in gaps to compact the array
+       i = 0;
+       while (maxparticle >= activeparticles)
+       {
+               *freeparticles[i++] = particles[maxparticle--];
+               while (maxparticle >= activeparticles && particles[maxparticle].die < cl.time)
+                       maxparticle--;
+       }
+       cl_numparticles = activeparticles;
+
+       if (pressureused)
+       {
+               activeparticles = 0;
+               for (i = 0, p = particles;i < cl_numparticles;i++, p++)
+                       if (p->pressure)
+                               freeparticles[activeparticles++] = p;
+
+               if (activeparticles)
+               {
+                       for (i = 0, p = particles;i < cl_numparticles;i++, p++)
+                       {
+                               for (j = 0;j < activeparticles;j++)
+                               {
+                                       if (freeparticles[j] != p)
+                                       {
+                                               float dist, diff[3];
+                                               VectorSubtract(p->org, freeparticles[j]->org, diff);
+                                               dist = DotProduct(diff, diff);
+                                               if (dist < 4096 && dist >= 1)
+                                               {
+                                                       dist = freeparticles[j]->scale * 4.0f * frametime / sqrt(dist);
+                                                       VectorMA(p->vel, dist, diff, p->vel);
+                                                       //dist = freeparticles[j]->scale * 4.0f * frametime / dist;
+                                                       //VectorMA(p->vel, dist, freeparticles[j]->vel, p->vel);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
index d441a61..d38ee27 100644 (file)
--- a/cl_tent.c
+++ b/cl_tent.c
@@ -21,19 +21,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
 
 #include "quakedef.h"
 
-cvar_t r_glowinglightning = {CVAR_SAVE, "r_glowinglightning", "1"};
+cvar_t cl_glowinglightning = {CVAR_SAVE, "cl_glowinglightning", "1"};
 
 int                    num_temp_entities;
 entity_t       cl_temp_entities[MAX_TEMP_ENTITIES];
 beam_t         cl_beams[MAX_BEAMS];
 
 
 int                    num_temp_entities;
 entity_t       cl_temp_entities[MAX_TEMP_ENTITIES];
 beam_t         cl_beams[MAX_BEAMS];
 
-sfx_t                  *cl_sfx_wizhit;
-sfx_t                  *cl_sfx_knighthit;
-sfx_t                  *cl_sfx_tink1;
-sfx_t                  *cl_sfx_ric1;
-sfx_t                  *cl_sfx_ric2;
-sfx_t                  *cl_sfx_ric3;
-sfx_t                  *cl_sfx_r_exp3;
+model_t                *cl_model_bolt = NULL;
+model_t                *cl_model_bolt2 = NULL;
+model_t                *cl_model_bolt3 = NULL;
+model_t                *cl_model_beam = NULL;
+
+sfx_t          *cl_sfx_wizhit;
+sfx_t          *cl_sfx_knighthit;
+sfx_t          *cl_sfx_tink1;
+sfx_t          *cl_sfx_ric1;
+sfx_t          *cl_sfx_ric2;
+sfx_t          *cl_sfx_ric3;
+sfx_t          *cl_sfx_r_exp3;
 
 /*
 =================
 
 /*
 =================
@@ -42,7 +47,7 @@ CL_ParseTEnt
 */
 void CL_InitTEnts (void)
 {
 */
 void CL_InitTEnts (void)
 {
-       Cvar_RegisterVariable(&r_glowinglightning);
+       Cvar_RegisterVariable(&cl_glowinglightning);
        cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
        cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
        cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
        cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
        cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
        cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
@@ -63,7 +68,7 @@ void CL_ParseBeam (model_t *m)
        vec3_t  start, end;
        beam_t  *b;
        int             i;
        vec3_t  start, end;
        beam_t  *b;
        int             i;
-       
+
        ent = MSG_ReadShort ();
        MSG_ReadVector(start);
        MSG_ReadVector(end);
        ent = MSG_ReadShort ();
        MSG_ReadVector(start);
        MSG_ReadVector(end);
@@ -96,25 +101,6 @@ void CL_ParseBeam (model_t *m)
        Con_Printf ("beam list overflow!\n");   
 }
 
        Con_Printf ("beam list overflow!\n");   
 }
 
-//void R_BlastParticles(vec3_t org, vec_t radius, vec_t power);
-void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count);
-void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel);
-void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type);
-
-// attempts to find the nearest non-solid location, used for explosions mainly
-void FindNonSolidLocation(vec3_t pos)
-{
-       if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
-       pos[0]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
-       pos[0]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
-       pos[0]-=1;
-       pos[1]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
-       pos[1]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
-       pos[1]-=1;
-       pos[2]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
-       pos[2]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
-       pos[2]-=1;
-}
 
 /*
 =================
 
 /*
 =================
@@ -138,21 +124,21 @@ void CL_ParseTEnt (void)
        {
        case TE_WIZSPIKE:                       // spike hitting wall
                MSG_ReadVector(pos);
        {
        case TE_WIZSPIKE:                       // spike hitting wall
                MSG_ReadVector(pos);
-               R_RunParticleEffect (pos, vec3_origin, 20, 30);
+               CL_RunParticleEffect (pos, vec3_origin, 20, 30);
                S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
                break;
                
        case TE_KNIGHTSPIKE:                    // spike hitting wall
                MSG_ReadVector(pos);
                S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
                break;
                
        case TE_KNIGHTSPIKE:                    // spike hitting wall
                MSG_ReadVector(pos);
-               R_RunParticleEffect (pos, vec3_origin, 226, 20);
+               CL_RunParticleEffect (pos, vec3_origin, 226, 20);
                S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
                break;
                
        case TE_SPIKE:                  // spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to spark shower
                S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
                break;
                
        case TE_SPIKE:                  // spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to spark shower
-               R_SparkShower(pos, vec3_origin, 15);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 10);
+               CL_SparkShower(pos, vec3_origin, 15);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 10);
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
                else
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
                else
@@ -169,8 +155,8 @@ void CL_ParseTEnt (void)
        case TE_SPIKEQUAD:                      // quad spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to spark shower
        case TE_SPIKEQUAD:                      // quad spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to spark shower
-               R_SparkShower(pos, vec3_origin, 15);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 10);
+               CL_SparkShower(pos, vec3_origin, 15);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 10);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                if ( rand() % 5 )
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                if ( rand() % 5 )
@@ -189,8 +175,8 @@ void CL_ParseTEnt (void)
        case TE_SUPERSPIKE:                     // super spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
        case TE_SUPERSPIKE:                     // super spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
-               R_SparkShower(pos, vec3_origin, 30);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 20);
+               CL_SparkShower(pos, vec3_origin, 30);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 20);
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
                else
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
                else
@@ -207,8 +193,8 @@ void CL_ParseTEnt (void)
        case TE_SUPERSPIKEQUAD:                 // quad super spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
        case TE_SUPERSPIKEQUAD:                 // quad super spike hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
-               R_SparkShower(pos, vec3_origin, 30);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 20);
+               CL_SparkShower(pos, vec3_origin, 30);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 20);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                if ( rand() % 5 )
                        S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
@@ -230,11 +216,11 @@ void CL_ParseTEnt (void)
                dir[1] = MSG_ReadChar ();
                dir[2] = MSG_ReadChar ();
                count = MSG_ReadByte (); // amount of particles
                dir[1] = MSG_ReadChar ();
                dir[2] = MSG_ReadChar ();
                count = MSG_ReadByte (); // amount of particles
-               R_BloodPuff(pos, dir, count);
+               CL_BloodPuff(pos, dir, count);
                break;
        case TE_BLOOD2: // blood puff
                MSG_ReadVector(pos);
                break;
        case TE_BLOOD2: // blood puff
                MSG_ReadVector(pos);
-               R_BloodPuff(pos, vec3_origin, 10);
+               CL_BloodPuff(pos, vec3_origin, 10);
                break;
        case TE_SPARK:  // spark shower
                MSG_ReadVector(pos);
                break;
        case TE_SPARK:  // spark shower
                MSG_ReadVector(pos);
@@ -242,7 +228,7 @@ void CL_ParseTEnt (void)
                dir[1] = MSG_ReadChar ();
                dir[2] = MSG_ReadChar ();
                count = MSG_ReadByte (); // amount of particles
                dir[1] = MSG_ReadChar ();
                dir[2] = MSG_ReadChar ();
                count = MSG_ReadByte (); // amount of particles
-               R_SparkShower(pos, dir, count);
+               CL_SparkShower(pos, dir, count);
                break;
                // LordHavoc: added for improved gore
        case TE_BLOODSHOWER:    // vaporized body
                break;
                // LordHavoc: added for improved gore
        case TE_BLOODSHOWER:    // vaporized body
@@ -250,7 +236,7 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(pos2); // maxs
                velspeed = MSG_ReadCoord (); // speed
                count = MSG_ReadShort (); // number of particles
                MSG_ReadVector(pos2); // maxs
                velspeed = MSG_ReadCoord (); // speed
                count = MSG_ReadShort (); // number of particles
-               R_BloodShower(pos, pos2, velspeed, count);
+               CL_BloodShower(pos, pos2, velspeed, count);
                break;
        case TE_PARTICLECUBE:   // general purpose particle effect
                MSG_ReadVector(pos); // mins
                break;
        case TE_PARTICLECUBE:   // general purpose particle effect
                MSG_ReadVector(pos); // mins
@@ -260,7 +246,7 @@ void CL_ParseTEnt (void)
                colorStart = MSG_ReadByte (); // color
                colorLength = MSG_ReadByte (); // gravity (1 or 0)
                velspeed = MSG_ReadCoord (); // randomvel
                colorStart = MSG_ReadByte (); // color
                colorLength = MSG_ReadByte (); // gravity (1 or 0)
                velspeed = MSG_ReadCoord (); // randomvel
-               R_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
+               CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
                break;
 
        case TE_PARTICLERAIN:   // general purpose particle effect
                break;
 
        case TE_PARTICLERAIN:   // general purpose particle effect
@@ -269,7 +255,7 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(dir); // dir
                count = MSG_ReadShort (); // number of particles
                colorStart = MSG_ReadByte (); // color
                MSG_ReadVector(dir); // dir
                count = MSG_ReadShort (); // number of particles
                colorStart = MSG_ReadByte (); // color
-               R_ParticleRain(pos, pos2, dir, count, colorStart, 0);
+               CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
                break;
 
        case TE_PARTICLESNOW:   // general purpose particle effect
                break;
 
        case TE_PARTICLESNOW:   // general purpose particle effect
@@ -278,36 +264,36 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(dir); // dir
                count = MSG_ReadShort (); // number of particles
                colorStart = MSG_ReadByte (); // color
                MSG_ReadVector(dir); // dir
                count = MSG_ReadShort (); // number of particles
                colorStart = MSG_ReadByte (); // color
-               R_ParticleRain(pos, pos2, dir, count, colorStart, 1);
+               CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
                break;
 
        case TE_GUNSHOT:                        // bullet hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
                break;
 
        case TE_GUNSHOT:                        // bullet hitting wall
                MSG_ReadVector(pos);
                // LordHavoc: changed to dust shower
-               R_SparkShower(pos, vec3_origin, 15);
-               //R_RunParticleEffect (pos, vec3_origin, 0, 20);
+               CL_SparkShower(pos, vec3_origin, 15);
+               //CL_RunParticleEffect (pos, vec3_origin, 0, 20);
                break;
 
        case TE_GUNSHOTQUAD:                    // quad bullet hitting wall
                MSG_ReadVector(pos);
                break;
 
        case TE_GUNSHOTQUAD:                    // quad bullet hitting wall
                MSG_ReadVector(pos);
-               R_SparkShower(pos, vec3_origin, 15);
+               CL_SparkShower(pos, vec3_origin, 15);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                break;
 
        case TE_EXPLOSION:                      // rocket explosion
                MSG_ReadVector(pos);
                CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
                break;
 
        case TE_EXPLOSION:                      // rocket explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 120);
                CL_AllocDlight (NULL, pos, 350, 1.0f, 0.8f, 0.4f, 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
 
        case TE_EXPLOSIONQUAD:                  // quad rocket explosion
                MSG_ReadVector(pos);
                CL_AllocDlight (NULL, pos, 350, 1.0f, 0.8f, 0.4f, 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
 
        case TE_EXPLOSIONQUAD:                  // quad rocket explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 480);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 480);
                CL_AllocDlight (NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
                CL_AllocDlight (NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
@@ -315,8 +301,8 @@ void CL_ParseTEnt (void)
                /*
        case TE_SMOKEEXPLOSION:                 // rocket explosion with a cloud of smoke
                MSG_ReadVector(pos);
                /*
        case TE_SMOKEEXPLOSION:                 // rocket explosion with a cloud of smoke
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, true);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, true);
                CL_AllocDlight (NULL, pos, 350, 1.0f, 0.8f, 0.4f, 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
                CL_AllocDlight (NULL, pos, 350, 1.0f, 0.8f, 0.4f, 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
@@ -324,18 +310,18 @@ void CL_ParseTEnt (void)
 
        case TE_EXPLOSION3:                             // Nehahra movie colored lighting explosion
                MSG_ReadVector(pos);
 
        case TE_EXPLOSION3:                             // Nehahra movie colored lighting explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 120);
                CL_AllocDlight (NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
 
        case TE_EXPLOSIONRGB:                   // colored lighting explosion
                MSG_ReadVector(pos);
                CL_AllocDlight (NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                break;
 
        case TE_EXPLOSIONRGB:                   // colored lighting explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_ParticleExplosion (pos, false);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_ParticleExplosion (pos, false);
+//             CL_BlastParticles (pos, 120, 120);
                color[0] = MSG_ReadByte() * (1.0 / 255.0);
                color[1] = MSG_ReadByte() * (1.0 / 255.0);
                color[2] = MSG_ReadByte() * (1.0 / 255.0);
                color[0] = MSG_ReadByte() * (1.0 / 255.0);
                color[1] = MSG_ReadByte() * (1.0 / 255.0);
                color[2] = MSG_ReadByte() * (1.0 / 255.0);
@@ -345,9 +331,9 @@ void CL_ParseTEnt (void)
 
        case TE_TAREXPLOSION:                   // tarbaby explosion
                MSG_ReadVector(pos);
 
        case TE_TAREXPLOSION:                   // tarbaby explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
-               R_BlobExplosion (pos);
-//             R_BlastParticles (pos, 120, 120);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
+               CL_BlobExplosion (pos);
+//             CL_BlastParticles (pos, 120, 120);
 
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                CL_AllocDlight (NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
 
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                CL_AllocDlight (NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
@@ -356,13 +342,13 @@ void CL_ParseTEnt (void)
 
        case TE_SMALLFLASH:
                MSG_ReadVector(pos);
 
        case TE_SMALLFLASH:
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
                CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
                break;
 
        case TE_CUSTOMFLASH:
                MSG_ReadVector(pos);
                CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
                break;
 
        case TE_CUSTOMFLASH:
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
                radius = MSG_ReadByte() * 8;
                velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
                color[0] = MSG_ReadByte() * (1.0 / 255.0);
                radius = MSG_ReadByte() * 8;
                velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
                color[0] = MSG_ReadByte() * (1.0 / 255.0);
@@ -375,53 +361,61 @@ void CL_ParseTEnt (void)
                MSG_ReadVector(pos);
                MSG_ReadVector(dir);
                count = MSG_ReadByte();
                MSG_ReadVector(pos);
                MSG_ReadVector(dir);
                count = MSG_ReadByte();
-               R_Flames(pos, dir, count);
+               CL_Flames(pos, dir, count);
                break;
 
        case TE_LIGHTNING1:                             // lightning bolts
                break;
 
        case TE_LIGHTNING1:                             // lightning bolts
-               CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
+               if (!cl_model_bolt)
+                       cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, true, false);
+               CL_ParseBeam (cl_model_bolt);
                break;
 
        case TE_LIGHTNING2:                             // lightning bolts
                break;
 
        case TE_LIGHTNING2:                             // lightning bolts
-               CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
+               if (!cl_model_bolt2)
+                       cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, true, false);
+               CL_ParseBeam (cl_model_bolt2);
                break;
                break;
-       
+
        case TE_LIGHTNING3:                             // lightning bolts
        case TE_LIGHTNING3:                             // lightning bolts
-               CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
+               if (!cl_model_bolt3)
+                       cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, true, false);
+               CL_ParseBeam (cl_model_bolt3);
                break;
 
                break;
 
-// PGM 01/21/97 
+// PGM 01/21/97
        case TE_BEAM:                           // grappling hook beam
        case TE_BEAM:                           // grappling hook beam
-               CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
+               if (!cl_model_beam)
+                       cl_model_beam = Mod_ForName("progs/beam.mdl", true, true, false);
+               CL_ParseBeam (cl_model_beam);
                break;
 // PGM 01/21/97
 
 // LordHavoc: for compatibility with the Nehahra movie...
        case TE_LIGHTNING4NEH:
                break;
 // PGM 01/21/97
 
 // LordHavoc: for compatibility with the Nehahra movie...
        case TE_LIGHTNING4NEH:
-               CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
+               CL_ParseBeam (Mod_ForName(MSG_ReadString(), true, false, false));
                break;
 
        case TE_LAVASPLASH:     
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
                break;
 
        case TE_LAVASPLASH:     
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
-               R_LavaSplash (pos);
+               CL_LavaSplash (pos);
                break;
        
        case TE_TELEPORT:
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
                break;
        
        case TE_TELEPORT:
                pos[0] = MSG_ReadCoord ();
                pos[1] = MSG_ReadCoord ();
                pos[2] = MSG_ReadCoord ();
-               R_TeleportSplash (pos);
+               CL_TeleportSplash (pos);
                break;
                
        case TE_EXPLOSION2:                             // color mapped explosion
                MSG_ReadVector(pos);
                break;
                
        case TE_EXPLOSION2:                             // color mapped explosion
                MSG_ReadVector(pos);
-               FindNonSolidLocation(pos);
+               Mod_FindNonSolidLocation(pos, cl.worldmodel);
                colorStart = MSG_ReadByte ();
                colorLength = MSG_ReadByte ();
                colorStart = MSG_ReadByte ();
                colorLength = MSG_ReadByte ();
-               R_ParticleExplosion2 (pos, colorStart, colorLength);
-//             R_BlastParticles (pos, 80, 80);
+               CL_ParticleExplosion2 (pos, colorStart, colorLength);
+//             CL_BlastParticles (pos, 80, 80);
                tempcolor = (byte *)&d_8to24table[(rand()%colorLength) + colorStart];
                CL_AllocDlight (NULL, pos, 350, tempcolor[0] * (1.0f / 255.0f), tempcolor[1] * (1.0f / 255.0f), tempcolor[2] * (1.0f / 255.0f), 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
                tempcolor = (byte *)&d_8to24table[(rand()%colorLength) + colorStart];
                CL_AllocDlight (NULL, pos, 350, tempcolor[0] * (1.0f / 255.0f), tempcolor[1] * (1.0f / 255.0f), tempcolor[2] * (1.0f / 255.0f), 700, 0.5);
                S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
@@ -453,7 +447,6 @@ entity_t *CL_NewTempEntity (void)
        ent->render.colormap = -1; // no special coloring
        ent->render.scale = 1;
        ent->render.alpha = 1;
        ent->render.colormap = -1; // no special coloring
        ent->render.scale = 1;
        ent->render.alpha = 1;
-       ent->render.colormod[0] = ent->render.colormod[1] = ent->render.colormod[2] = 1;
        return ent;
 }
 
        return ent;
 }
 
@@ -523,8 +516,8 @@ void CL_UpdateTEnts (void)
                        ent->render.angles[1] = yaw;
                        ent->render.angles[2] = rand()%360;
 
                        ent->render.angles[1] = yaw;
                        ent->render.angles[2] = rand()%360;
 
-                       if (r_glowinglightning.value > 0)
-                               CL_AllocDlight(&ent->render, ent->render.origin, lhrandom(100, 120), r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, 0, 0);
+                       if (cl_glowinglightning.value > 0)
+                               CL_AllocDlight(&ent->render, ent->render.origin, lhrandom(200, 240), cl_glowinglightning.value * 0.25f, cl_glowinglightning.value * 0.25f, cl_glowinglightning.value * 0.25f, 0, 0);
 
                        VectorMA(org, 30, dist, org);
                        d -= 30;
 
                        VectorMA(org, 30, dist, org);
                        d -= 30;
index 4b469bb..d9dbbe5 100644 (file)
--- a/client.h
+++ b/client.h
@@ -8,7 +8,7 @@ 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
 
 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.  
+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.
 
@@ -19,6 +19,70 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 // client.h
 
 */
 // client.h
 
+typedef struct frameblend_s
+{
+       int frame;
+       float lerp;
+}
+frameblend_t;
+
+// LordHavoc: nothing in this structure is persistant, it may be overwritten by the client every frame, for persistant data use entity_lerp_t.
+typedef struct entity_render_s
+{
+       vec3_t  origin;                 // location
+       vec3_t  angles;                 // orientation
+       float   alpha;                  // opacity (alpha) of the model
+       float   scale;                  // size the model is shown
+
+       model_t *model;                 // NULL = no model
+       int             frame;                  // current uninterpolated animation frame (for things which do not use interpolation)
+       int             colormap;               // entity shirt and pants colors
+       int             effects;                // light, particles, etc
+       int             skinnum;                // for Alias models
+       int             flags;                  // render flags
+
+       // these are copied from the persistent data
+       int             frame1;                 // frame that the model is interpolating from
+       int             frame2;                 // frame that the model is interpolating to
+       double  framelerp;              // interpolation factor, usually computed from frame2time
+       double  frame1time;             // time frame1 began playing (for framegroup animations)
+       double  frame2time;             // time frame2 began playing (for framegroup animations)
+
+       // calculated by the renderer (but not persistent)
+       int             visframe;               // if visframe == r_framecount, it is visible
+       vec3_t  mins, maxs;             // calculated during R_AddModelEntities
+       frameblend_t    frameblend[4]; // 4 frame numbers (-1 if not used) and their blending scalers (0-1), if interpolation is not desired, use frame instead
+}
+entity_render_t;
+
+typedef struct entity_persistent_s
+{
+       // particles
+       vec3_t  trail_origin;   // trail rendering
+       float   trail_time;             // trail rendering
+
+       // interpolated animation
+       int             modelindex;             // lerp resets when model changes
+       int             frame1;                 // frame that the model is interpolating from
+       int             frame2;                 // frame that the model is interpolating to
+       double  framelerp;              // interpolation factor, usually computed from frame2time
+       double  frame1time;             // time frame1 began playing (for framegroup animations)
+       double  frame2time;             // time frame2 began playing (for framegroup animations)
+}
+entity_persistent_t;
+
+typedef struct entity_s
+{
+       entity_state_t state_baseline;  // baseline state (default values)
+       entity_state_t state_previous;  // previous state (interpolating from this)
+       entity_state_t state_current;   // current state (interpolating to this)
+
+       entity_persistent_t persistent; // used for regenerating parts of render
+
+       entity_render_t render; // the only data the renderer should know about
+}
+entity_t;
+
 typedef struct
 {
        vec3_t  viewangles;
 typedef struct
 {
        vec3_t  viewangles;
@@ -64,8 +128,6 @@ typedef struct
 
 #define        SIGNONS         4                       // signon messages to receive before connected
 
 
 #define        SIGNONS         4                       // signon messages to receive before connected
 
-#include "r_light.h"
-
 #define        MAX_BEAMS       24
 typedef struct
 {
 #define        MAX_BEAMS       24
 typedef struct
 {
@@ -96,7 +158,7 @@ typedef struct
 {
        cactive_t       state;
 
 {
        cactive_t       state;
 
-// personalization data sent to server 
+// personalization data sent to server
        char            mapstring[MAX_QPATH];
        char            spawnparms[MAX_MAPSTRING];      // to restart a level
 
        char            mapstring[MAX_QPATH];
        char            spawnparms[MAX_MAPSTRING];      // to restart a level
 
@@ -134,7 +196,7 @@ typedef struct
 {
        int                     movemessages;   // since connecting to this server
                                                                // throw out the first couple, so the player
 {
        int                     movemessages;   // since connecting to this server
                                                                // throw out the first couple, so the player
-                                                               // doesn't accidentally do something the 
+                                                               // doesn't accidentally do something the
                                                                // first frame
        usercmd_t       cmd;                    // last command sent to the server
 
                                                                // first frame
        usercmd_t       cmd;                    // last command sent to the server
 
@@ -154,7 +216,7 @@ typedef struct
        vec3_t          mviewangles[2]; // during demo playback viewangles is lerped
                                                                // between these
        vec3_t          viewangles;
        vec3_t          mviewangles[2]; // during demo playback viewangles is lerped
                                                                // between these
        vec3_t          viewangles;
-       
+
        vec3_t          mvelocity[2];   // update by server, used for lean+bob
                                                                // (0 is newest)
        vec3_t          velocity;               // lerped between mvelocity[0] and [1]
        vec3_t          mvelocity[2];   // update by server, used for lean+bob
                                                                // (0 is newest)
        vec3_t          velocity;               // lerped between mvelocity[0] and [1]
@@ -179,7 +241,7 @@ typedef struct
        int                     intermission;   // don't change view angle, full screen, etc
        int                     completed_time; // latched at intermission start
 
        int                     intermission;   // don't change view angle, full screen, etc
        int                     completed_time; // latched at intermission start
 
-       double          mtime[2];               // the timestamp of last two messages   
+       double          mtime[2];               // the timestamp of last two messages
        double          time;                   // clients view of time, should be between
                                                                // servertime and oldservertime to generate
                                                                // a lerp point for other data
        double          time;                   // clients view of time, should be between
                                                                // servertime and oldservertime to generate
                                                                // a lerp point for other data
@@ -215,6 +277,7 @@ typedef struct
 }
 client_state_t;
 
 }
 client_state_t;
 
+extern mempool_t *cl_scores_mempool;
 
 //
 // cvars
 
 //
 // cvars
@@ -266,26 +329,22 @@ extern    lightstyle_t    cl_lightstyle[MAX_LIGHTSTYLES];
 extern entity_t                cl_temp_entities[MAX_TEMP_ENTITIES];
 extern beam_t                  cl_beams[MAX_BEAMS];
 
 extern entity_t                cl_temp_entities[MAX_TEMP_ENTITIES];
 extern beam_t                  cl_beams[MAX_BEAMS];
 
-//=============================================================================
-
 #include "cl_light.h"
 
 #include "cl_light.h"
 
+//=============================================================================
+
 //
 // cl_main
 //
 
 //
 // cl_main
 //
 
-extern void CL_Init (void);
+void CL_Init (void);
 
 
-extern void CL_EstablishConnection (char *host);
-extern void CL_Signon1 (void);
-extern void CL_Signon2 (void);
-extern void CL_Signon3 (void);
-extern void CL_Signon4 (void);
+void CL_EstablishConnection (char *host);
 
 
-extern void CL_Disconnect (void);
-extern void CL_Disconnect_f (void);
-extern void CL_NextDemo (void);
+void CL_Disconnect (void);
+void CL_Disconnect_f (void);
 
 
+// LordHavoc: fixme: move this to r_refdef?
 // LordHavoc: raised this from 256 to the maximum possible number of entities visible
 #define MAX_VISEDICTS (MAX_EDICTS + MAX_STATIC_ENTITIES + MAX_TEMP_ENTITIES)
 extern int                     cl_numvisedicts;
 // LordHavoc: raised this from 256 to the maximum possible number of entities visible
 #define MAX_VISEDICTS (MAX_EDICTS + MAX_STATIC_ENTITIES + MAX_TEMP_ENTITIES)
 extern int                     cl_numvisedicts;
@@ -305,62 +364,134 @@ extern   kbutton_t       in_mlook, in_klook;
 extern         kbutton_t       in_strafe;
 extern         kbutton_t       in_speed;
 
 extern         kbutton_t       in_strafe;
 extern         kbutton_t       in_speed;
 
-extern void CL_InitInput (void);
-extern void CL_SendCmd (void);
-extern void CL_SendMove (usercmd_t *cmd);
+void CL_InitInput (void);
+void CL_SendCmd (void);
+void CL_SendMove (usercmd_t *cmd);
 
 
-extern void CL_ParseTEnt (void);
-extern void CL_UpdateTEnts (void);
-extern void CL_DoEffects (void);
+void CL_LerpUpdate(entity_t *e, int frame, int modelindex);
+void CL_ParseTEnt (void);
+void CL_UpdateTEnts (void);
 
 
-extern entity_t *CL_NewTempEntity (void);
+entity_t *CL_NewTempEntity (void);
 
 
-extern void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate);
+void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate);
 
 
-extern void CL_ClearState (void);
+void CL_ClearState (void);
 
 
 
 
-extern int  CL_ReadFromServer (void);
-extern void CL_WriteToServer (usercmd_t *cmd);
-extern void CL_BaseMove (usercmd_t *cmd);
+int  CL_ReadFromServer (void);
+void CL_WriteToServer (usercmd_t *cmd);
+void CL_BaseMove (usercmd_t *cmd);
 
 
 
 
-extern float CL_KeyState (kbutton_t *key);
-extern char *Key_KeynumToString (int keynum);
+float CL_KeyState (kbutton_t *key);
+char *Key_KeynumToString (int keynum);
 
 //
 // cl_demo.c
 //
 
 //
 // cl_demo.c
 //
-extern void CL_StopPlayback (void);
-extern int CL_GetMessage (void);
+void CL_StopPlayback (void);
+int CL_GetMessage (void);
 
 
-extern void CL_Stop_f (void);
-extern void CL_Record_f (void);
-extern void CL_PlayDemo_f (void);
-extern void CL_TimeDemo_f (void);
+void CL_NextDemo (void);
+void CL_Stop_f (void);
+void CL_Record_f (void);
+void CL_PlayDemo_f (void);
+void CL_TimeDemo_f (void);
 
 //
 // cl_parse.c
 //
 
 //
 // cl_parse.c
 //
-extern void CL_Parse_Init(void);
-extern void CL_ParseServerMessage(void);
-extern void CL_BitProfile_f(void);
+void CL_Parse_Init(void);
+void CL_ParseServerMessage(void);
+void CL_BitProfile_f(void);
 
 //
 // view
 //
 
 //
 // view
 //
-extern void V_StartPitchDrift (void);
-extern void V_StopPitchDrift (void);
+void V_StartPitchDrift (void);
+void V_StopPitchDrift (void);
 
 
-extern void V_RenderView (void);
-extern void V_UpdateBlends (void);
-extern void V_Register (void);
-extern void V_ParseDamage (void);
-extern void V_SetContentsColor (int contents);
+void V_RenderView (void);
+void V_UpdateBlends (void);
+void V_Register (void);
+void V_ParseDamage (void);
+void V_SetContentsColor (int contents);
 
 
 //
 // cl_tent
 //
 
 
 //
 // cl_tent
 //
-extern void CL_InitTEnts (void);
-extern void CL_SignonReply (void);
+void CL_InitTEnts (void);
+
+//
+// cl_part
+//
+
+#define PARTICLE_INVALID 0
+#define PARTICLE_BILLBOARD 1
+#define PARTICLE_UPRIGHT_FACING 2
+#define PARTICLE_ORIENTED_DOUBLESIDED 3
+
+typedef struct renderparticle_s
+{
+       int                     tex;
+       int                     orientation;
+       int                     dynlight;
+       float           scale;
+       float           org[3];
+       float           dir[3];
+       float           color[4];
+}
+renderparticle_t;
+
+void CL_Particles_Clear(void);
+void CL_Particles_Init(void);
+
+void CL_ParseParticleEffect (void);
+void CL_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
+void CL_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent);
+void CL_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent);
+void CL_SparkShower (vec3_t org, vec3_t dir, int count);
+void CL_BloodPuff (vec3_t org, vec3_t vel, int count);
+void CL_FlameCube (vec3_t mins, vec3_t maxs, int count);
+void CL_Flames (vec3_t org, vec3_t vel, int count);
+void CL_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count);
+void CL_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel);
+void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type);
+void CL_EntityParticles (entity_t *ent);
+void CL_BlobExplosion (vec3_t org);
+void CL_ParticleExplosion (vec3_t org, int smoke);
+void CL_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength);
+void CL_LavaSplash (vec3_t org);
+void CL_TeleportSplash (vec3_t org);
+void CL_MoveParticles(void);
+void CL_UpdateDecals(void);
+void R_MoveExplosions(void);
+void R_NewExplosion(vec3_t org);
+
+//
+// cl_decal
+//
+
+typedef struct renderdecal_s
+{
+       entity_render_t *ent;
+       int tex;
+       int surface;
+       float scale;
+       vec3_t org;
+       vec3_t dir;
+       float color[4];
+}
+renderdecal_t;
+
+void CL_Decals_Clear(void);
+void CL_Decals_Init(void);
+void CL_Decal(vec3_t origin, int tex, float scale, float red, float green, float blue, float alpha);
+
+// if contents is not zero, it will impact on content changes
+// (leafs matching contents are considered empty, others are solid)
+extern int traceline_endcontents; // set by TraceLine
+float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int contents);
+
diff --git a/cmd.c b/cmd.c
index 71f476b..293155d 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -8,7 +8,7 @@ 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
 
 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.  
+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.
 
@@ -21,8 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
 
 #include "quakedef.h"
 
-void Cmd_ForwardToServer (void);
-
 #define        MAX_ALIAS_NAME  32
 
 typedef struct cmdalias_s
 #define        MAX_ALIAS_NAME  32
 
 typedef struct cmdalias_s
@@ -32,12 +30,11 @@ typedef struct cmdalias_s
        char    *value;
 } cmdalias_t;
 
        char    *value;
 } cmdalias_t;
 
-cmdalias_t     *cmd_alias;
+static cmdalias_t *cmd_alias;
 
 
-int trashtest;
-int *trashspot;
+static qboolean cmd_wait;
 
 
-qboolean       cmd_wait;
+static mempool_t *cmd_mempool;
 
 //=============================================================================
 
 
 //=============================================================================
 
@@ -50,7 +47,7 @@ next frame.  This allows commands like:
 bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
 ============
 */
 bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
 ============
 */
-void Cmd_Wait_f (void)
+static void Cmd_Wait_f (void)
 {
        cmd_wait = true;
 }
 {
        cmd_wait = true;
 }
@@ -63,7 +60,7 @@ void Cmd_Wait_f (void)
 =============================================================================
 */
 
 =============================================================================
 */
 
-sizebuf_t      cmd_text;
+static sizebuf_t       cmd_text;
 
 /*
 ============
 
 /*
 ============
@@ -72,7 +69,8 @@ Cbuf_Init
 */
 void Cbuf_Init (void)
 {
 */
 void Cbuf_Init (void)
 {
-       SZ_Alloc (&cmd_text, 8192);             // space for commands and script files
+       // LordHavoc: inreased this from 8192 to 32768
+       SZ_Alloc (&cmd_text, 32768, "command buffer"); // space for commands and script files
 }
 
 
 }
 
 
@@ -86,7 +84,7 @@ Adds command text at the end of the buffer
 void Cbuf_AddText (char *text)
 {
        int             l;
 void Cbuf_AddText (char *text)
 {
        int             l;
-       
+
        l = strlen (text);
 
        if (cmd_text.cursize + l >= cmd_text.maxsize)
        l = strlen (text);
 
        if (cmd_text.cursize + l >= cmd_text.maxsize)
@@ -123,10 +121,10 @@ void Cbuf_InsertText (char *text)
        }
        else
                temp = NULL;    // shut up compiler
        }
        else
                temp = NULL;    // shut up compiler
-               
+
 // add the entire text of the file
        Cbuf_AddText (text);
 // add the entire text of the file
        Cbuf_AddText (text);
-       
+
 // add the copied off data
        if (templen)
        {
 // add the copied off data
        if (templen)
        {
@@ -146,7 +144,7 @@ void Cbuf_Execute (void)
        char    *text;
        char    line[1024];
        int             quotes;
        char    *text;
        char    line[1024];
        int             quotes;
-       
+
        while (cmd_text.cursize)
        {
 // find a \n or ; line break
        while (cmd_text.cursize)
        {
 // find a \n or ; line break
@@ -162,11 +160,10 @@ void Cbuf_Execute (void)
                        if (text[i] == '\n')
                                break;
                }
                        if (text[i] == '\n')
                                break;
                }
-                       
-                               
+
                memcpy (line, text, i);
                line[i] = 0;
                memcpy (line, text, 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
 // 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
@@ -182,7 +179,7 @@ void Cbuf_Execute (void)
 
 // execute the command line
                Cmd_ExecuteString (line, src_command);
 
 // execute the command line
                Cmd_ExecuteString (line, src_command);
-               
+
                if (cmd_wait)
                {       // skip out while text still remains in buffer, leaving it
                        // for next frame
                if (cmd_wait)
                {       // skip out while text still remains in buffer, leaving it
                        // for next frame
@@ -215,7 +212,7 @@ void Cmd_StuffCmds_f (void)
        int             i, j;
        int             s;
        char    *text, *build, c;
        int             i, j;
        int             s;
        char    *text, *build, c;
-               
+
        if (Cmd_Argc () != 1)
        {
                Con_Printf ("stuffcmds : execute command line parameters\n");
        if (Cmd_Argc () != 1)
        {
                Con_Printf ("stuffcmds : execute command line parameters\n");
@@ -232,7 +229,7 @@ void Cmd_StuffCmds_f (void)
        }
        if (!s)
                return;
        }
        if (!s)
                return;
-               
+
        text = Z_Malloc (s+1);
        text[0] = 0;
        for (i=1 ; i<com_argc ; i++)
        text = Z_Malloc (s+1);
        text[0] = 0;
        for (i=1 ; i<com_argc ; i++)
@@ -243,11 +240,11 @@ void Cmd_StuffCmds_f (void)
                if (i != com_argc-1)
                        strcat (text, " ");
        }
                if (i != com_argc-1)
                        strcat (text, " ");
        }
-       
+
 // pull out the commands
        build = Z_Malloc (s+1);
        build[0] = 0;
 // pull out the commands
        build = Z_Malloc (s+1);
        build[0] = 0;
-       
+
        for (i=0 ; i<s-1 ; i++)
        {
                if (text[i] == '+')
        for (i=0 ; i<s-1 ; i++)
        {
                if (text[i] == '+')
@@ -259,17 +256,17 @@ void Cmd_StuffCmds_f (void)
 
                        c = text[j];
                        text[j] = 0;
 
                        c = text[j];
                        text[j] = 0;
-                       
+
                        strcat (build, text+i);
                        strcat (build, "\n");
                        text[j] = c;
                        i = j-1;
                }
        }
                        strcat (build, text+i);
                        strcat (build, "\n");
                        text[j] = c;
                        i = j-1;
                }
        }
-       
+
        if (build[0])
                Cbuf_InsertText (build);
        if (build[0])
                Cbuf_InsertText (build);
-       
+
        Z_Free (text);
        Z_Free (build);
 }
        Z_Free (text);
        Z_Free (build);
 }
@@ -280,7 +277,7 @@ void Cmd_StuffCmds_f (void)
 Cmd_Exec_f
 ===============
 */
 Cmd_Exec_f
 ===============
 */
-void Cmd_Exec_f (void)
+static void Cmd_Exec_f (void)
 {
        char    *f;
 
 {
        char    *f;
 
@@ -290,16 +287,16 @@ void Cmd_Exec_f (void)
                return;
        }
 
                return;
        }
 
-       f = (char *)COM_LoadMallocFile (Cmd_Argv(1), false);
+       f = (char *)COM_LoadFile (Cmd_Argv(1), false);
        if (!f)
        {
                Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
                return;
        }
        Con_Printf ("execing %s\n",Cmd_Argv(1));
        if (!f)
        {
                Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
                return;
        }
        Con_Printf ("execing %s\n",Cmd_Argv(1));
-       
+
        Cbuf_InsertText (f);
        Cbuf_InsertText (f);
-       qfree(f);
+       Mem_Free(f);
 }
 
 
 }
 
 
@@ -310,10 +307,10 @@ Cmd_Echo_f
 Just prints the rest of the line to the console
 ===============
 */
 Just prints the rest of the line to the console
 ===============
 */
-void Cmd_Echo_f (void)
+static void Cmd_Echo_f (void)
 {
        int             i;
 {
        int             i;
-       
+
        for (i=1 ; i<Cmd_Argc() ; i++)
                Con_Printf ("%s ",Cmd_Argv(i));
        Con_Printf ("\n");
        for (i=1 ; i<Cmd_Argc() ; i++)
                Con_Printf ("%s ",Cmd_Argv(i));
        Con_Printf ("\n");
@@ -327,16 +324,16 @@ Creates a new command that executes a command string (possibly ; seperated)
 ===============
 */
 
 ===============
 */
 
-char *CopyString (char *in)
+static char *CopyString (char *in)
 {
        char    *out;
 {
        char    *out;
-       
+
        out = Z_Malloc (strlen(in)+1);
        strcpy (out, in);
        return out;
 }
 
        out = Z_Malloc (strlen(in)+1);
        strcpy (out, in);
        return out;
 }
 
-void Cmd_Alias_f (void)
+static void Cmd_Alias_f (void)
 {
        cmdalias_t      *a;
        char            cmd[1024];
 {
        cmdalias_t      *a;
        char            cmd[1024];
@@ -374,7 +371,7 @@ void Cmd_Alias_f (void)
                a->next = cmd_alias;
                cmd_alias = a;
        }
                a->next = cmd_alias;
                cmd_alias = a;
        }
-       strcpy (a->name, s);    
+       strcpy (a->name, s);
 
 // copy the rest of the command line
        cmd[0] = 0;             // start out with a null string
 
 // copy the rest of the command line
        cmd[0] = 0;             // start out with a null string
@@ -386,7 +383,7 @@ void Cmd_Alias_f (void)
                        strcat (cmd, " ");
        }
        strcat (cmd, "\n");
                        strcat (cmd, " ");
        }
        strcat (cmd, "\n");
-       
+
        a->value = CopyString (cmd);
 }
 
        a->value = CopyString (cmd);
 }
 
@@ -408,15 +405,15 @@ typedef struct cmd_function_s
 
 #define        MAX_ARGS                80
 
 
 #define        MAX_ARGS                80
 
-static int                     cmd_argc;
-static char            *cmd_argv[MAX_ARGS];
-static char            *cmd_null_string = "";
-static char            *cmd_args = NULL;
+static int cmd_argc;
+static char *cmd_argv[MAX_ARGS];
+static char *cmd_null_string = "";
+static char *cmd_args = NULL;
 
 
-cmd_source_t   cmd_source;
+cmd_source_t cmd_source;
 
 
 
 
-static cmd_function_t  *cmd_functions;         // possible commands to execute
+static cmd_function_t *cmd_functions;          // possible commands to execute
 
 /*
 ========
 
 /*
 ========
@@ -427,7 +424,7 @@ Cmd_List
 
 ========
 */
 
 ========
 */
-void Cmd_List_f (void)
+static void Cmd_List_f (void)
 {
        cmd_function_t  *cmd;
        char                    *partial;
 {
        cmd_function_t  *cmd;
        char                    *partial;
@@ -464,6 +461,8 @@ Cmd_Init
 */
 void Cmd_Init (void)
 {
 */
 void Cmd_Init (void)
 {
+       cmd_mempool = Mem_AllocPool("commands");
+
 //
 // register our commands
 //
 //
 // register our commands
 //
@@ -497,7 +496,7 @@ char        *Cmd_Argv (int arg)
 {
        if (arg >= cmd_argc )
                return cmd_null_string;
 {
        if (arg >= cmd_argc )
                return cmd_null_string;
-       return cmd_argv[arg];   
+       return cmd_argv[arg];
 }
 
 /*
 }
 
 /*
@@ -518,17 +517,17 @@ Cmd_TokenizeString
 Parses the given string into command line tokens.
 ============
 */
 Parses the given string into command line tokens.
 ============
 */
-void Cmd_TokenizeString (char *text)
+static void Cmd_TokenizeString (char *text)
 {
        int             i;
 {
        int             i;
-       
+
 // clear the args from the last string
        for (i=0 ; i<cmd_argc ; i++)
                Z_Free (cmd_argv[i]);
 // clear the args from the last string
        for (i=0 ; i<cmd_argc ; i++)
                Z_Free (cmd_argv[i]);
-               
+
        cmd_argc = 0;
        cmd_args = NULL;
        cmd_argc = 0;
        cmd_args = NULL;
-       
+
        while (1)
        {
 // skip whitespace up to a /n
        while (1)
        {
 // skip whitespace up to a /n
@@ -536,7 +535,7 @@ void Cmd_TokenizeString (char *text)
                {
                        text++;
                }
                {
                        text++;
                }
-               
+
                if (*text == '\n')
                {       // a newline seperates commands in the buffer
                        text++;
                if (*text == '\n')
                {       // a newline seperates commands in the buffer
                        text++;
@@ -545,10 +544,10 @@ void Cmd_TokenizeString (char *text)
 
                if (!*text)
                        return;
 
                if (!*text)
                        return;
-       
+
                if (cmd_argc == 1)
                         cmd_args = text;
                if (cmd_argc == 1)
                         cmd_args = text;
-                       
+
                text = COM_Parse (text);
                if (!text)
                        return;
                text = COM_Parse (text);
                if (!text)
                        return;
@@ -560,7 +559,7 @@ void Cmd_TokenizeString (char *text)
                        cmd_argc++;
                }
        }
                        cmd_argc++;
                }
        }
-       
+
 }
 
 
 }
 
 
@@ -572,17 +571,17 @@ Cmd_AddCommand
 void   Cmd_AddCommand (char *cmd_name, xcommand_t function)
 {
        cmd_function_t  *cmd;
 void   Cmd_AddCommand (char *cmd_name, xcommand_t function)
 {
        cmd_function_t  *cmd;
-       
-       if (host_initialized)   // because hunk allocation would get stomped
-               Sys_Error ("Cmd_AddCommand after host_initialized");
-               
+
+//     if (host_initialized)   // because hunk allocation would get stomped
+//             Sys_Error ("Cmd_AddCommand after host_initialized");
+
 // fail if the command is a variable name
        if (Cvar_VariableString(cmd_name)[0])
        {
                Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
                return;
        }
 // fail if the command is a variable name
        if (Cvar_VariableString(cmd_name)[0])
        {
                Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
                return;
        }
-       
+
 // fail if the command already exists
        for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
        {
 // fail if the command already exists
        for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
        {
@@ -593,7 +592,7 @@ void        Cmd_AddCommand (char *cmd_name, xcommand_t function)
                }
        }
 
                }
        }
 
-       cmd = Hunk_AllocName (sizeof(cmd_function_t), "commands");
+       cmd = Mem_Alloc(cmd_mempool, sizeof(cmd_function_t));
        cmd->name = cmd_name;
        cmd->function = function;
        cmd->next = cmd_functions;
        cmd->name = cmd_name;
        cmd->function = function;
        cmd->next = cmd_functions;
@@ -610,10 +609,8 @@ qboolean   Cmd_Exists (char *cmd_name)
        cmd_function_t  *cmd;
 
        for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
        cmd_function_t  *cmd;
 
        for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
-       {
                if (!strcmp (cmd_name,cmd->name))
                        return true;
                if (!strcmp (cmd_name,cmd->name))
                        return true;
-       }
 
        return false;
 }
 
        return false;
 }
@@ -629,12 +626,12 @@ char *Cmd_CompleteCommand (char *partial)
 {
        cmd_function_t  *cmd;
        int                             len;
 {
        cmd_function_t  *cmd;
        int                             len;
-       
+
        len = strlen(partial);
        len = strlen(partial);
-       
+
        if (!len)
                return NULL;
        if (!len)
                return NULL;
-               
+
 // check functions
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncmp(partial, cmd->name, len))
 // check functions
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncmp(partial, cmd->name, len))
@@ -652,19 +649,18 @@ char *Cmd_CompleteCommand (char *partial)
        Thanks to taniwha
 
 */
        Thanks to taniwha
 
 */
-int
-Cmd_CompleteCountPossible (char *partial)
+int Cmd_CompleteCountPossible (char *partial)
 {
        cmd_function_t  *cmd;
        int                             len;
        int                             h;
 {
        cmd_function_t  *cmd;
        int                             len;
        int                             h;
-       
+
        h = 0;
        len = strlen(partial);
        h = 0;
        len = strlen(partial);
-       
+
        if (!len)
                return 0;
        if (!len)
                return 0;
-       
+
        // Loop through the command list and count all partial matches
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncasecmp(partial, cmd->name, len))
        // Loop through the command list and count all partial matches
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncasecmp(partial, cmd->name, len))
@@ -682,8 +678,7 @@ Cmd_CompleteCountPossible (char *partial)
        Thanks to taniwha
 
 */
        Thanks to taniwha
 
 */
-char   **
-Cmd_CompleteBuildList (char *partial)
+char **Cmd_CompleteBuildList (char *partial)
 {
        cmd_function_t  *cmd;
        int                             len = 0;
 {
        cmd_function_t  *cmd;
        int                             len = 0;
@@ -692,7 +687,7 @@ Cmd_CompleteBuildList (char *partial)
        char                    **buf;
 
        len = strlen(partial);
        char                    **buf;
 
        len = strlen(partial);
-       buf = qmalloc(sizeofbuf + sizeof (char *));
+       buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (char *));
        // Loop through the alias list and print all matches
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncasecmp(partial, cmd->name, len))
        // Loop through the alias list and print all matches
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncasecmp(partial, cmd->name, len))
@@ -711,8 +706,7 @@ Cmd_CompleteBuildList (char *partial)
        Thanks to taniwha
 
 */
        Thanks to taniwha
 
 */
-char
-*Cmd_CompleteAlias (char * partial)
+char *Cmd_CompleteAlias (char * partial)
 {
        cmdalias_t      *alias;
        int                     len;
 {
        cmdalias_t      *alias;
        int                     len;
@@ -739,8 +733,7 @@ char
        Thanks to taniwha
 
 */
        Thanks to taniwha
 
 */
-int
-Cmd_CompleteAliasCountPossible (char *partial)
+int Cmd_CompleteAliasCountPossible (char *partial)
 {
        cmdalias_t      *alias;
        int                     len;
 {
        cmdalias_t      *alias;
        int                     len;
@@ -770,8 +763,7 @@ Cmd_CompleteAliasCountPossible (char *partial)
        Thanks to taniwha
 
 */
        Thanks to taniwha
 
 */
-char   **
-Cmd_CompleteAliasBuildList (char *partial)
+char **Cmd_CompleteAliasBuildList (char *partial)
 {
        cmdalias_t      *alias;
        int                     len = 0;
 {
        cmdalias_t      *alias;
        int                     len = 0;
@@ -780,7 +772,7 @@ Cmd_CompleteAliasBuildList (char *partial)
        char            **buf;
 
        len = strlen(partial);
        char            **buf;
 
        len = strlen(partial);
-       buf = qmalloc(sizeofbuf + sizeof (char *));
+       buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (char *));
        // Loop through the alias list and print all matches
        for (alias = cmd_alias; alias; alias = alias->next)
                if (!strncasecmp(partial, alias->name, len))
        // Loop through the alias list and print all matches
        for (alias = cmd_alias; alias; alias = alias->next)
                if (!strncasecmp(partial, alias->name, len))
@@ -799,13 +791,13 @@ FIXME: lookupnoadd the token to speed search?
 ============
 */
 void   Cmd_ExecuteString (char *text, cmd_source_t src)
 ============
 */
 void   Cmd_ExecuteString (char *text, cmd_source_t src)
-{      
+{
        cmd_function_t  *cmd;
        cmdalias_t              *a;
 
        cmd_source = src;
        Cmd_TokenizeString (text);
        cmd_function_t  *cmd;
        cmdalias_t              *a;
 
        cmd_source = src;
        Cmd_TokenizeString (text);
-                       
+
 // execute the command line
        if (!Cmd_Argc())
                return;         // no tokens
 // execute the command line
        if (!Cmd_Argc())
                return;         // no tokens
@@ -829,11 +821,10 @@ void      Cmd_ExecuteString (char *text, cmd_source_t src)
                        return;
                }
        }
                        return;
                }
        }
-       
+
 // check cvars
        if (!Cvar_Command ())
                Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
 // check cvars
        if (!Cvar_Command ())
                Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
-       
 }
 
 
 }
 
 
@@ -851,7 +842,7 @@ void Cmd_ForwardToServer (void)
                Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
                return;
        }
                Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
                return;
        }
-       
+
        if (cls.demoplayback)
                return;         // not really connected
 
        if (cls.demoplayback)
                return;         // not really connected
 
@@ -880,14 +871,14 @@ where the given parameter apears, or 0 if not present
 int Cmd_CheckParm (char *parm)
 {
        int i;
 int Cmd_CheckParm (char *parm)
 {
        int i;
-       
+
        if (!parm)
                Sys_Error ("Cmd_CheckParm: NULL");
 
        for (i = 1; i < Cmd_Argc (); i++)
                if (!Q_strcasecmp (parm, Cmd_Argv (i)))
                        return i;
        if (!parm)
                Sys_Error ("Cmd_CheckParm: NULL");
 
        for (i = 1; i < Cmd_Argc (); i++)
                if (!Q_strcasecmp (parm, Cmd_Argv (i)))
                        return i;
-                       
+
        return 0;
 }
 
        return 0;
 }
 
diff --git a/cmd.h b/cmd.h
index ba2796e..640afc5 100644 (file)
--- a/cmd.h
+++ b/cmd.h
@@ -116,7 +116,7 @@ int Cmd_CheckParm (char *parm);
 // Returns the position (1 to argc-1) in the command's argument list
 // where the given parameter apears, or 0 if not present
 
 // Returns the position (1 to argc-1) in the command's argument list
 // where the given parameter apears, or 0 if not present
 
-void Cmd_TokenizeString (char *text);
+//void Cmd_TokenizeString (char *text);
 // Takes a null terminated string.  Does not need to be /n terminated.
 // breaks the string up into arg tokens.
 
 // Takes a null terminated string.  Does not need to be /n terminated.
 // breaks the string up into arg tokens.
 
index 5c73c03..2711267 100644 (file)
--- a/common.c
+++ b/common.c
@@ -31,32 +31,34 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #define NUM_SAFE_ARGVS  7
 
 
 #define NUM_SAFE_ARGVS  7
 
-static char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
-static char     *argvdummy = " ";
+static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
+static char *argvdummy = " ";
 
 
-static char     *safeargvs[NUM_SAFE_ARGVS] =
+static char *safeargvs[NUM_SAFE_ARGVS] =
        {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-window"};
 
 cvar_t registered = {0, "registered","0"};
 cvar_t cmdline = {0, "cmdline","0"};
 
        {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-window"};
 
 cvar_t registered = {0, "registered","0"};
 cvar_t cmdline = {0, "cmdline","0"};
 
-qboolean        com_modified;   // set true if using non-id files
+mempool_t *pak_mempool;
 
 
-//qboolean             proghack;
+qboolean com_modified;   // set true if using non-id files
 
 
-//int             static_registered = 1;  // only for startup check, then set
+//qboolean proghack;
 
 
-qboolean               msg_suppress_1 = 0;
+//int static_registered = 1;  // only for startup check, then set
+
+qboolean msg_suppress_1 = 0;
 
 void COM_InitFilesystem (void);
 
 
 void COM_InitFilesystem (void);
 
-char   com_token[1024];
-int            com_argc;
-char   **com_argv;
+char com_token[1024];
+int com_argc;
+char **com_argv;
 
 // LordHavoc: made commandline 1024 characters instead of 256
 #define CMDLINE_LENGTH 1024
 
 // LordHavoc: made commandline 1024 characters instead of 256
 #define CMDLINE_LENGTH 1024
-char   com_cmdline[CMDLINE_LENGTH];
+char com_cmdline[CMDLINE_LENGTH];
 
 int gamemode;
 char *gamename;
 
 int gamemode;
 char *gamename;
@@ -192,7 +194,7 @@ int Q_strcmp (char *s1, char *s2)
                s1++;
                s2++;
        }
                s1++;
                s2++;
        }
-       
+
        return -1;
 }
 
        return -1;
 }
 
@@ -209,7 +211,7 @@ int Q_strncmp (char *s1, char *s2, int count)
                s1++;
                s2++;
        }
                s1++;
                s2++;
        }
-       
+
        return -1;
 }
 */
        return -1;
 }
 */
@@ -224,7 +226,7 @@ int Q_strncasecmp (char *s1, char *s2, int n)
 
                if (!n--)
                        return 0;               // strings are equal until end point
 
                if (!n--)
                        return 0;               // strings are equal until end point
-               
+
                if (c1 != c2)
                {
                        if (c1 >= 'a' && c1 <= 'z')
                if (c1 != c2)
                {
                        if (c1 >= 'a' && c1 <= 'z')
@@ -239,7 +241,7 @@ int Q_strncasecmp (char *s1, char *s2, int n)
 //              s1++;
 //              s2++;
        }
 //              s1++;
 //              s2++;
        }
-       
+
        return -1;
 }
 
        return -1;
 }
 
@@ -410,10 +412,12 @@ short   ShortSwap (short l)
        return (b1<<8) + b2;
 }
 
        return (b1<<8) + b2;
 }
 
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
 short   ShortNoSwap (short l)
 {
        return l;
 }
 short   ShortNoSwap (short l)
 {
        return l;
 }
+#endif
 
 int    LongSwap (int l)
 {
 
 int    LongSwap (int l)
 {
@@ -427,10 +431,12 @@ int    LongSwap (int l)
        return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
 }
 
        return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
 }
 
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
 int     LongNoSwap (int l)
 {
        return l;
 }
 int     LongNoSwap (int l)
 {
        return l;
 }
+#endif
 
 float FloatSwap (float f)
 {
 
 float FloatSwap (float f)
 {
@@ -439,8 +445,8 @@ float FloatSwap (float f)
                float   f;
                byte    b[4];
        } dat1, dat2;
                float   f;
                byte    b[4];
        } dat1, dat2;
-       
-       
+
+
        dat1.f = f;
        dat2.b[0] = dat1.b[3];
        dat2.b[1] = dat1.b[2];
        dat1.f = f;
        dat2.b[0] = dat1.b[3];
        dat2.b[1] = dat1.b[2];
@@ -449,10 +455,12 @@ float FloatSwap (float f)
        return dat2.f;
 }
 
        return dat2.f;
 }
 
+#if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
 float FloatNoSwap (float f)
 {
        return f;
 }
 float FloatNoSwap (float f)
 {
        return f;
 }
+#endif
 
 /*
 ==============================================================================
 
 /*
 ==============================================================================
@@ -496,7 +504,7 @@ void MSG_WriteByte (sizebuf_t *sb, int c)
 void MSG_WriteShort (sizebuf_t *sb, int c)
 {
        byte    *buf;
 void MSG_WriteShort (sizebuf_t *sb, int c)
 {
        byte    *buf;
-       
+
 //#ifdef PARANOID
 //     if (c < ((short)0x8000) || c > (short)0x7fff)
 //             Sys_Error ("MSG_WriteShort: range error");
 //#ifdef PARANOID
 //     if (c < ((short)0x8000) || c > (short)0x7fff)
 //             Sys_Error ("MSG_WriteShort: range error");
@@ -510,7 +518,7 @@ void MSG_WriteShort (sizebuf_t *sb, int c)
 void MSG_WriteLong (sizebuf_t *sb, int c)
 {
        byte    *buf;
 void MSG_WriteLong (sizebuf_t *sb, int c)
 {
        byte    *buf;
-       
+
        buf = SZ_GetSpace (sb, 4);
        buf[0] = c&0xff;
        buf[1] = (c>>8)&0xff;
        buf = SZ_GetSpace (sb, 4);
        buf[0] = c&0xff;
        buf[1] = (c>>8)&0xff;
@@ -525,11 +533,11 @@ void MSG_WriteFloat (sizebuf_t *sb, float f)
                float   f;
                int     l;
        } dat;
                float   f;
                int     l;
        } dat;
-       
-       
+
+
        dat.f = f;
        dat.l = LittleLong (dat.l);
        dat.f = f;
        dat.l = LittleLong (dat.l);
-       
+
        SZ_Write (sb, &dat.l, 4);
 }
 
        SZ_Write (sb, &dat.l, 4);
 }
 
@@ -556,18 +564,29 @@ void MSG_WriteCoord (sizebuf_t *sb, float f)
        if (dpprotocol)
                MSG_WriteFloat(sb, f);
        else
        if (dpprotocol)
                MSG_WriteFloat(sb, f);
        else
-               MSG_WriteShort (sb, (int)(f*8.0f + 0.5f));
+       {
+               if (f >= 0)
+                       MSG_WriteShort (sb, (int)(f*8.0f + 0.5f));
+               else
+                       MSG_WriteShort (sb, (int)(f*8.0f - 0.5f));
+       }
 }
 
 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
 {
 }
 
 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
 {
-       MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
+       if (f >= 0)
+               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
+       else
+               MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
 }
 
 }
 
-// LordHavoc: round to nearest value, rather than rounding down, fixes crosshair problem
+// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
 void MSG_WriteAngle (sizebuf_t *sb, float f)
 {
 void MSG_WriteAngle (sizebuf_t *sb, float f)
 {
-       MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
+       if (f >= 0)
+               MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
+       else
+               MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
 }
 
 //
 }
 
 //
@@ -598,7 +617,7 @@ int MSG_ReadChar (void)
                
        c = (signed char)net_message.data[msg_readcount];
        msg_readcount++;
                
        c = (signed char)net_message.data[msg_readcount];
        msg_readcount++;
-       
+
        return c;
 }
 
        return c;
 }
 
@@ -613,7 +632,7 @@ int MSG_ReadByte (void)
                msg_badread = true;
                return -1;
        }
                msg_badread = true;
                return -1;
        }
-               
+
        c = (unsigned char)net_message.data[msg_readcount];
        msg_readcount++;
        
        c = (unsigned char)net_message.data[msg_readcount];
        msg_readcount++;
        
@@ -624,7 +643,7 @@ int MSG_ReadByte (void)
 int MSG_ReadShort (void)
 {
        int     c;
 int MSG_ReadShort (void)
 {
        int     c;
-       
+
        if (msg_readcount+2 > net_message.cursize)
        {
                msg_badread = true;
        if (msg_readcount+2 > net_message.cursize)
        {
                msg_badread = true;
@@ -737,11 +756,12 @@ float MSG_ReadPreciseAngle (void)
 
 //===========================================================================
 
 
 //===========================================================================
 
-void SZ_Alloc (sizebuf_t *buf, int startsize)
+void SZ_Alloc (sizebuf_t *buf, int startsize, char *name)
 {
        if (startsize < 256)
                startsize = 256;
 {
        if (startsize < 256)
                startsize = 256;
-       buf->data = Hunk_AllocName (startsize, "sizebuf");
+       buf->mempool = Mem_AllocPool(name);
+       buf->data = Mem_Alloc(buf->mempool, startsize);
        buf->maxsize = startsize;
        buf->cursize = 0;
 }
        buf->maxsize = startsize;
        buf->cursize = 0;
 }
@@ -749,9 +769,9 @@ void SZ_Alloc (sizebuf_t *buf, int startsize)
 
 void SZ_Free (sizebuf_t *buf)
 {
 
 void SZ_Free (sizebuf_t *buf)
 {
-//      Z_Free (buf->data);
-//      buf->data = NULL;
-//      buf->maxsize = 0;
+       Mem_FreePool(&buf->mempool);
+       buf->data = NULL;
+       buf->maxsize = 0;
        buf->cursize = 0;
 }
 
        buf->cursize = 0;
 }
 
@@ -763,18 +783,18 @@ void SZ_Clear (sizebuf_t *buf)
 void *SZ_GetSpace (sizebuf_t *buf, int length)
 {
        void    *data;
 void *SZ_GetSpace (sizebuf_t *buf, int length)
 {
        void    *data;
-       
+
        if (buf->cursize + length > buf->maxsize)
        {
                if (!buf->allowoverflow)
                        Host_Error ("SZ_GetSpace: overflow without allowoverflow set - use -zone on the commandline for more zone memory, default: 128k (quake original default was 48k)");
        if (buf->cursize + length > buf->maxsize)
        {
                if (!buf->allowoverflow)
                        Host_Error ("SZ_GetSpace: overflow without allowoverflow set - use -zone on the commandline for more zone memory, default: 128k (quake original default was 48k)");
-               
+
                if (length > buf->maxsize)
                        Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
                if (length > buf->maxsize)
                        Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
-                       
+
                buf->overflowed = true;
                Con_Printf ("SZ_GetSpace: overflow");
                buf->overflowed = true;
                Con_Printf ("SZ_GetSpace: overflow");
-               SZ_Clear (buf); 
+               SZ_Clear (buf);
        }
 
        data = buf->data + buf->cursize;
        }
 
        data = buf->data + buf->cursize;
@@ -813,7 +833,7 @@ COM_SkipPath
 char *COM_SkipPath (char *pathname)
 {
        char    *last;
 char *COM_SkipPath (char *pathname)
 {
        char    *last;
-       
+
        last = pathname;
        while (*pathname)
        {
        last = pathname;
        while (*pathname)
        {
@@ -1056,7 +1076,7 @@ void COM_CheckRegistered (void)
 //                     Sys_Error ("You must have the registered version to use modified games");
                return;
        }
 //                     Sys_Error ("You must have the registered version to use modified games");
                return;
        }
-       
+
 //     Cvar_Set ("cmdline", com_cmdline);
        Cvar_Set ("registered", "1");
 //     static_registered = 1;
 //     Cvar_Set ("cmdline", com_cmdline);
        Cvar_Set ("registered", "1");
 //     static_registered = 1;
@@ -1166,42 +1186,6 @@ void COM_InitArgv (int argc, char **argv)
 }
 
 
 }
 
 
-unsigned int qmalloctotal_alloc, qmalloctotal_alloccount, qmalloctotal_free, qmalloctotal_freecount;
-
-void *qmalloc(unsigned int size)
-{
-       unsigned int *mem;
-       qmalloctotal_alloc += size;
-       qmalloctotal_alloccount++;
-       mem = malloc(size+sizeof(unsigned int));
-       if (!mem)
-               return mem;
-       *mem = size;
-       return (void *)(mem + 1);
-}
-
-void qfree(void *mem)
-{
-       unsigned int *m;
-       if (!mem)
-               return;
-       m = mem;
-       m--; // back up to size
-       qmalloctotal_free += *m; // size
-       qmalloctotal_freecount++;
-       free(m);
-}
-
-extern void GL_TextureStats_PrintTotal(void);
-extern int hunk_low_used, hunk_high_used, hunk_size;
-void COM_Memstats_f(void)
-{
-       Con_Printf("%i malloc calls totalling %i bytes (%.4gMB)\n%i free calls totalling %i bytes (%.4gMB)\n%i bytes (%.4gMB) currently allocated\n", qmalloctotal_alloccount, qmalloctotal_alloc, qmalloctotal_alloc / 1048576.0, qmalloctotal_freecount, qmalloctotal_free, qmalloctotal_free / 1048576.0, qmalloctotal_alloc - qmalloctotal_free, (qmalloctotal_alloc - qmalloctotal_free) / 1048576.0);
-       GL_TextureStats_PrintTotal();
-       Con_Printf ("%i bytes (%.4gMB) of %.4gMB hunk in use\n", hunk_low_used + hunk_high_used, (hunk_low_used + hunk_high_used) / 1048576.0, hunk_size / 1048576.0);
-}
-
-
 extern void Mathlib_Init(void);
 
 /*
 extern void Mathlib_Init(void);
 
 /*
@@ -1209,12 +1193,12 @@ extern void Mathlib_Init(void);
 COM_Init
 ================
 */
 COM_Init
 ================
 */
-void COM_Init (char *basedir)
+void COM_Init (void)
 {
 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
        byte    swaptest[2] = {1,0};
 
 {
 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
        byte    swaptest[2] = {1,0};
 
-// set the byte swapping variables in a portable manner 
+// set the byte swapping variables in a portable manner
        if ( *(short *)swaptest == 1)
        {
                BigShort = ShortSwap;
        if ( *(short *)swaptest == 1)
        {
                BigShort = ShortSwap;
@@ -1235,10 +1219,11 @@ void COM_Init (char *basedir)
        }
 #endif
 
        }
 #endif
 
+       pak_mempool = Mem_AllocPool("paks");
+
        Cvar_RegisterVariable (&registered);
        Cvar_RegisterVariable (&cmdline);
        Cmd_AddCommand ("path", COM_Path_f);
        Cvar_RegisterVariable (&registered);
        Cvar_RegisterVariable (&cmdline);
        Cmd_AddCommand ("path", COM_Path_f);
-       Cmd_AddCommand ("memstats", COM_Memstats_f);
 
        Mathlib_Init();
 
 
        Mathlib_Init();
 
@@ -1297,16 +1282,18 @@ int     com_filesize;
 
 typedef struct
 {
 
 typedef struct
 {
-       char    name[MAX_QPATH];
-       int             filepos, filelen;
+       char name[MAX_QPATH];
+       int filepos, filelen;
 } packfile_t;
 
 typedef struct pack_s
 {
 } packfile_t;
 
 typedef struct pack_s
 {
-       char    filename[MAX_OSPATH];
-       int             handle;
-       int             numfiles;
-       packfile_t      *files;
+       char filename[MAX_OSPATH];
+       int handle;
+       int numfiles;
+       packfile_t *files;
+       mempool_t *mempool;
+       struct pack_s *next;
 } pack_t;
 
 //
 } pack_t;
 
 //
@@ -1314,19 +1301,21 @@ typedef struct pack_s
 //
 typedef struct
 {
 //
 typedef struct
 {
-       char    name[56];
-       int             filepos, filelen;
+       char name[56];
+       int filepos, filelen;
 } dpackfile_t;
 
 typedef struct
 {
 } dpackfile_t;
 
 typedef struct
 {
-       char    id[4];
-       int             dirofs;
-       int             dirlen;
+       char id[4];
+       int dirofs;
+       int dirlen;
 } dpackheader_t;
 
 } dpackheader_t;
 
-// LordHavoc: was 2048, increased to 16384 and changed info[MAX_PACK_FILES] to a temporary malloc to avoid stack overflows
-#define MAX_FILES_IN_PACK       16384
+// LordHavoc: was 2048, increased to 65536 and changed info[MAX_PACK_FILES] to a temporary alloc
+#define MAX_FILES_IN_PACK       65536
+
+pack_t *packlist = NULL;
 
 #if CACHEENABLE
 char   com_cachedir[MAX_OSPATH];
 
 #if CACHEENABLE
 char   com_cachedir[MAX_OSPATH];
@@ -1335,8 +1324,8 @@ char      com_gamedir[MAX_OSPATH];
 
 typedef struct searchpath_s
 {
 
 typedef struct searchpath_s
 {
-       char    filename[MAX_OSPATH];
-       pack_t  *pack;          // only one of filename / pack will be used
+       char filename[MAX_OSPATH];
+       pack_t *pack;          // only one of filename / pack will be used
        struct searchpath_s *next;
 } searchpath_t;
 
        struct searchpath_s *next;
 } searchpath_t;
 
@@ -1351,7 +1340,7 @@ COM_Path_f
 void COM_Path_f (void)
 {
        searchpath_t    *s;
 void COM_Path_f (void)
 {
        searchpath_t    *s;
-       
+
        Con_Printf ("Current search path:\n");
        for (s=com_searchpaths ; s ; s=s->next)
        {
        Con_Printf ("Current search path:\n");
        for (s=com_searchpaths ; s ; s=s->next)
        {
@@ -1431,7 +1420,7 @@ void COM_CopyFile (char *netpath, char *cachepath)
        int             in, out;
        int             remaining, count;
        char    buf[4096];
        int             in, out;
        int             remaining, count;
        char    buf[4096];
-       
+
        remaining = Sys_FileOpenRead (netpath, &in);            
        COM_CreatePath (cachepath);     // create directories up to the cache file
        out = Sys_FileOpenWrite (cachepath);
        remaining = Sys_FileOpenRead (netpath, &in);            
        COM_CreatePath (cachepath);     // create directories up to the cache file
        out = Sys_FileOpenWrite (cachepath);
@@ -1631,10 +1620,9 @@ Filename are reletive to the quake directory.
 Always appends a 0 byte.
 ============
 */
 Always appends a 0 byte.
 ============
 */
-cache_user_t   *loadcache;
 byte                   *loadbuf;
 int                            loadsize;
 byte                   *loadbuf;
 int                            loadsize;
-byte *COM_LoadFile (char *path, int usehunk, qboolean quiet)
+byte *COM_LoadFile (char *path, qboolean quiet)
 {
        QFile             *h;
        byte    *buf;
 {
        QFile             *h;
        byte    *buf;
@@ -1650,64 +1638,22 @@ byte *COM_LoadFile (char *path, int usehunk, qboolean quiet)
                return NULL;
 
        loadsize = len;
                return NULL;
 
        loadsize = len;
-       
+
 // extract the filename base name for hunk tag
        COM_FileBase (path, base);
 // extract the filename base name for hunk tag
        COM_FileBase (path, base);
-       
-       switch (usehunk)
-       {
-       case 1:
-               buf = Hunk_AllocName (len+1, va("%s (file)", path));
-               if (!buf)
-                       Sys_Error ("COM_LoadFile: not enough hunk space for %s (size %i)", path, len);
-               break;
-//     case 0:
-//             buf = Z_Malloc (len+1);
-//             if (!buf)
-//                     Sys_Error ("COM_LoadFile: not enough zone space for %s (size %i)", path, len);
-//             break;
-//     case 3:
-//             buf = Cache_Alloc (loadcache, len+1, base);
-//             if (!buf)
-//                     Sys_Error ("COM_LoadFile: not enough cache space for %s (size %i)", path, len);
-//             break;
-       case 5:
-               buf = qmalloc (len+1);
-               if (!buf)
-                       Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
-               break;
-       default:
-               Sys_Error ("COM_LoadFile: bad usehunk");
-               break;
-       }
+
+       buf = Mem_Alloc(tempmempool, len+1);
+       if (!buf)
+               Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
 
        ((byte *)buf)[len] = 0;
 
 
        ((byte *)buf)[len] = 0;
 
-       Qread (h, buf, len);                     
+       Qread (h, buf, len);
        Qclose (h);
 
        return buf;
 }
 
        Qclose (h);
 
        return buf;
 }
 
-byte *COM_LoadHunkFile (char *path, qboolean quiet)
-{
-       return COM_LoadFile (path, 1, quiet);
-}
-
-// LordHavoc: returns malloc'd memory
-byte *COM_LoadMallocFile (char *path, qboolean quiet)
-{
-       return COM_LoadFile (path, 5, quiet);
-}
-
-/*
-void COM_LoadCacheFile (char *path, struct cache_user_s *cu, qboolean quiet)
-{
-       loadcache = cu;
-       COM_LoadFile (path, 3, quiet);
-}
-*/
-
 /*
 =================
 COM_LoadPackFile
 /*
 =================
 COM_LoadPackFile
@@ -1722,51 +1668,54 @@ pack_t *COM_LoadPackFile (char *packfile)
 {
        dpackheader_t   header;
        int                             i;