]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - clvm_cmds.c
more stupid error code passing
[xonotic/darkplaces.git] / clvm_cmds.c
index 11277881d36056fe5d11884eb3335d6b48e57a49..fc0ad58546b7577db59a85e59cb0674d8f31f2e8 100644 (file)
@@ -21,6 +21,7 @@
 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
 
 extern cvar_t v_flipped;
+extern cvar_t r_equalize_entities_fullbright;
 
 sfx_t *S_FindName(const char *name);
 int Sbar_GetSortedPlayerIndex (int index);
@@ -261,7 +262,7 @@ static void VM_CL_traceline (void)
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
                PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
 
-       trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
+       trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
 
        CL_VM_SetTraceGlobals(&trace, svent);
 }
@@ -299,7 +300,7 @@ static void VM_CL_tracebox (void)
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
                PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
 
-       trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
+       trace = CL_TraceBox(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
 
        CL_VM_SetTraceGlobals(&trace, svent);
 }
@@ -334,7 +335,7 @@ trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
                VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
                VectorScale (tossent->fields.client->velocity, 0.05, move);
                VectorAdd (tossent->fields.client->origin, move, end);
-               trace = CL_Move (tossent->fields.client->origin, tossent->fields.client->mins, tossent->fields.client->maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
+               trace = CL_TraceBox(tossent->fields.client->origin, tossent->fields.client->mins, tossent->fields.client->maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
                VectorCopy (trace.endpos, tossent->fields.client->origin);
 
                if (trace.fraction < 1)
@@ -522,7 +523,7 @@ static void VM_CL_droptofloor (void)
        VectorCopy (ent->fields.client->origin, end);
        end[2] -= 256;
 
-       trace = CL_Move(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+       trace = CL_TraceBox(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
 
        if (trace.fraction != 1)
        {
@@ -551,7 +552,7 @@ static void VM_CL_lightstyle (void)
                VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
                return;
        }
-       strlcpy (cl.lightstyle[i].map,  MSG_ReadString(), sizeof (cl.lightstyle[i].map));
+       strlcpy (cl.lightstyle[i].map, c, sizeof (cl.lightstyle[i].map));
        cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
        cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
 }
@@ -601,7 +602,7 @@ realcheck:
        start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
        start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
        stop[2] = start[2] - 2*sv_stepheight.value;
-       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+       trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
 
        if (trace.fraction == 1.0)
                return;
@@ -615,7 +616,7 @@ realcheck:
                        start[0] = stop[0] = x ? maxs[0] : mins[0];
                        start[1] = stop[1] = y ? maxs[1] : mins[1];
 
-                       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+                       trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
 
                        if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
                                bottom = trace.endpos[2];
@@ -726,6 +727,7 @@ extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
 void VM_CL_R_AddEntities (void)
 {
+       double t = Sys_DoubleTime();
        int                     i, drawmask;
        prvm_edict_t *ed;
        VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
@@ -750,13 +752,18 @@ void VM_CL_R_AddEntities (void)
                        continue;
                CSQC_AddRenderEdict(ed);
        }
+
+       // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
+       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
 }
 
 //#302 void(entity ent) addentity (EXT_CSQC)
 void VM_CL_R_AddEntity (void)
 {
+       double t = Sys_DoubleTime();
        VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
        CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
+       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
 }
 
 //#303 float(float property, ...) setproperty (EXT_CSQC)
@@ -844,13 +851,13 @@ void VM_CL_R_SetView (void)
                CSQC_R_RecalcView();
                break;
        case VF_DRAWWORLD:
-               cl.csqc_vidvars.drawworld = k;
+               cl.csqc_vidvars.drawworld = k != 0;
                break;
        case VF_DRAWENGINESBAR:
-               cl.csqc_vidvars.drawenginesbar = k;
+               cl.csqc_vidvars.drawenginesbar = k != 0;
                break;
        case VF_DRAWCROSSHAIR:
-               cl.csqc_vidvars.drawcrosshair = k;
+               cl.csqc_vidvars.drawcrosshair = k != 0;
                break;
        case VF_CL_VIEWANGLES:
                VectorCopy(f, cl.viewangles);
@@ -881,6 +888,7 @@ void VM_CL_R_SetView (void)
 //#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC)
 void VM_CL_R_AddDynamicLight (void)
 {
+       double t = Sys_DoubleTime();
        vec_t *org;
        float radius = 300;
        vec_t *col;
@@ -927,6 +935,7 @@ void VM_CL_R_AddDynamicLight (void)
 
        R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights++];
+       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
 }
 
 //============================================================================
@@ -1142,7 +1151,7 @@ static void VM_CL_getkeybind (void)
 static void VM_CL_setcursormode (void)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
-       cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
+       cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0) != 0;
        cl_ignoremousemoves = 2;
 }
 
@@ -1434,6 +1443,11 @@ static void VM_CL_makestatic (void)
                staticent->render.scale = 1;
                if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
                if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
+               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glowmod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.glowmod);
+               if (!VectorLength2(staticent->render.colormod))
+                       VectorSet(staticent->render.colormod, 1, 1, 1);
+               if (!VectorLength2(staticent->render.glowmod))
+                       VectorSet(staticent->render.glowmod, 1, 1, 1);
 
                renderflags = 0;
                if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
@@ -1448,11 +1462,22 @@ static void VM_CL_makestatic (void)
                        Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], staticent->render.scale);
 
                // either fullbright or lit
-               if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
-                       staticent->render.flags |= RENDER_LIGHT;
+               if(!r_fullbright.integer)
+               {
+                       if (!(staticent->render.effects & EF_FULLBRIGHT))
+                               staticent->render.flags |= RENDER_LIGHT;
+                       else if(r_equalize_entities_fullbright.integer)
+                               staticent->render.flags |= RENDER_LIGHT | RENDER_EQUALIZE;
+               }
                // turn off shadows from transparent objects
                if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
                        staticent->render.flags |= RENDER_SHADOW;
+               if (staticent->render.effects & EF_NODEPTHTEST)
+                       staticent->render.flags |= RENDER_NODEPTHTEST;
+               if (staticent->render.effects & EF_ADDITIVE)
+                       staticent->render.flags |= RENDER_ADDITIVE;
+               if (staticent->render.effects & EF_DOUBLESIDED)
+                       staticent->render.flags |= RENDER_DOUBLESIDED;
 
                CL_UpdateRenderEntity(&staticent->render);
        }
@@ -2219,12 +2244,19 @@ int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
        return 1;
 }
 
+int CL_GetPitchSign(prvm_edict_t *ent)
+{
+       dp_model_t *model;
+       if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
+               return -1;
+       return 1;
+}
+
 void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
        prvm_eval_t *val;
        float scale;
-       float pitchsign;
-       dp_model_t *model;
+       float pitchsign = 1;
 
        scale = 1;
        val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
@@ -2236,18 +2268,17 @@ void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatri
                Matrix4x4_CreateFromQuakeEntity(out, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], scale * cl_viewmodel_scale.value);
        else
        {
-               pitchsign = 1;
-               if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
-                       pitchsign = -1;
+               pitchsign = CL_GetPitchSign(ent);
                Matrix4x4_CreateFromQuakeEntity(out, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], pitchsign * ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
        }
 }
 
-
 int CL_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
 {
        int frame;
+       int ret;
        dp_model_t *model;
+       entity_render_t cheatentity;
        if (tagindex >= 0
         && (model = CL_GetModelFromEdict(ent))
         && model->animscenes)
@@ -2256,7 +2287,15 @@ int CL_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out
                frame = (int)ent->fields.client->frame;
                if (frame < 0 || frame >= model->numframes)
                        frame = 0;
-               return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
+               // now we'll do some CHEATING
+               memset(&cheatentity, 0, sizeof(cheatentity));
+               cheatentity.model = model;
+               CL_LoadFrameGroupBlend(ent, &cheatentity);
+               R_LerpAnimation(&cheatentity);
+               ret = CL_BlendTagMatrix(&cheatentity, tagindex, out);
+               if(ret)
+                       *out = identitymatrix;
+               return ret;
        }
        *out = identitymatrix;
        return 0;
@@ -2443,6 +2482,448 @@ void VM_CL_gettaginfo (void)
 
 //============================================================================
 
+//====================
+// DP_CSQC_SPAWNPARTICLE
+// a QC hook to engine's CL_NewParticle
+//====================
+
+// particle theme struct
+typedef struct vmparticletheme_s
+{
+       unsigned short typeindex;
+       qboolean initialized;
+       pblend_t blendmode;
+       porientation_t orientation;
+       int color1;
+       int color2;
+       int tex;
+       float size;
+       float sizeincrease;
+       int alpha;
+       int alphafade;
+       float gravity;
+       float bounce;
+       float airfriction;
+       float liquidfriction;
+       float originjitter;
+       float velocityjitter;
+       qboolean qualityreduction;
+       float lifetime;
+       float stretch;
+       int staincolor1;
+       int staincolor2;
+       int staintex;
+       float delayspawn;
+       float delaycollision;
+}vmparticletheme_t;
+
+// particle spawner
+typedef struct vmparticlespawner_s
+{
+       mempool_t                       *pool;
+       qboolean                        initialized;
+       qboolean                        verified;
+       vmparticletheme_t       *themes;
+       int                                     max_themes;
+       // global addresses
+       float *particle_type;
+       float *particle_blendmode; 
+       float *particle_orientation;
+       float *particle_color1;
+       float *particle_color2;
+       float *particle_tex;
+       float *particle_size;
+       float *particle_sizeincrease;
+       float *particle_alpha;
+       float *particle_alphafade;
+       float *particle_time;
+       float *particle_gravity;
+       float *particle_bounce;
+       float *particle_airfriction;
+       float *particle_liquidfriction;
+       float *particle_originjitter;
+       float *particle_velocityjitter;
+       float *particle_qualityreduction;
+       float *particle_stretch;
+       float *particle_staincolor1;
+       float *particle_staincolor2;
+       float *particle_staintex;
+       float *particle_delayspawn;
+       float *particle_delaycollision;
+}vmparticlespawner_t;
+
+vmparticlespawner_t vmpartspawner;
+
+// TODO: automatic max_themes grow
+static void VM_InitParticleSpawner (int maxthemes)
+{
+       prvm_eval_t *val;
+
+       // bound max themes to not be an insane value
+       if (maxthemes < 4)
+               maxthemes = 4;
+       if (maxthemes > 2048)
+               maxthemes = 2048;
+       // allocate and set up structure
+       if (vmpartspawner.initialized) // reallocate
+       {
+               Mem_FreePool(&vmpartspawner.pool);
+               memset(&vmpartspawner, 0, sizeof(vmparticlespawner_t));
+       }
+       vmpartspawner.pool = Mem_AllocPool("VMPARTICLESPAWNER", 0, NULL);
+       vmpartspawner.themes = (vmparticletheme_t *)Mem_Alloc(vmpartspawner.pool, sizeof(vmparticletheme_t)*maxthemes);
+       vmpartspawner.max_themes = maxthemes;
+       vmpartspawner.initialized = true;
+       vmpartspawner.verified = true;
+       // get field addresses for fast querying (we can do 1000 calls of spawnparticle in a frame)
+       #define getglobal(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = &val->_float; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; }
+       #define getglobalvector(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = (float *)val->vector; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; }
+       getglobal(particle_type, "particle_type");
+       getglobal(particle_blendmode, "particle_blendmode");
+       getglobal(particle_orientation, "particle_orientation");
+       getglobalvector(particle_color1, "particle_color1");
+       getglobalvector(particle_color2, "particle_color2");
+       getglobal(particle_tex, "particle_tex");
+       getglobal(particle_size, "particle_size");
+       getglobal(particle_sizeincrease, "particle_sizeincrease");
+       getglobal(particle_alpha, "particle_alpha");
+       getglobal(particle_alphafade, "particle_alphafade");
+       getglobal(particle_time, "particle_time");
+       getglobal(particle_gravity, "particle_gravity");
+       getglobal(particle_bounce, "particle_bounce");
+       getglobal(particle_airfriction, "particle_airfriction");
+       getglobal(particle_liquidfriction, "particle_liquidfriction");
+       getglobal(particle_originjitter, "particle_originjitter");
+       getglobal(particle_velocityjitter, "particle_velocityjitter");
+       getglobal(particle_qualityreduction, "particle_qualityreduction");
+       getglobal(particle_stretch, "particle_stretch");
+       getglobalvector(particle_staincolor1, "particle_staincolor1");
+       getglobalvector(particle_staincolor2, "particle_staincolor2");
+       getglobal(particle_staintex, "particle_staintex");
+       getglobal(particle_delayspawn, "particle_delayspawn");
+       getglobal(particle_delaycollision, "particle_delaycollision");
+       #undef getglobal
+       #undef getglobalvector
+}
+
+// reset particle theme to default values
+static void VM_ResetParticleTheme (vmparticletheme_t *theme)
+{
+       theme->initialized = true;
+       theme->typeindex = pt_static;
+       theme->blendmode = PBLEND_ADD;
+       theme->orientation = PARTICLE_BILLBOARD;
+       theme->color1 = 0x808080;
+       theme->color2 = 0xFFFFFF;
+       theme->tex = 63;
+       theme->size = 2;
+       theme->sizeincrease = 0;
+       theme->alpha = 256;
+       theme->alphafade = 512;
+       theme->gravity = 0.0f;
+       theme->bounce = 0.0f;
+       theme->airfriction = 1.0f;
+       theme->liquidfriction = 4.0f;
+       theme->originjitter = 0.0f;
+       theme->velocityjitter = 0.0f;
+       theme->qualityreduction = false;
+       theme->lifetime = 4;
+       theme->stretch = 1;
+       theme->staincolor1 = -1;
+       theme->staincolor2 = -1;
+       theme->staintex = -1;
+       theme->delayspawn = 0.0f;
+       theme->delaycollision = 0.0f;
+}
+
+// particle theme -> QC globals
+void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme)
+{
+       *vmpartspawner.particle_type = theme->typeindex;
+       *vmpartspawner.particle_blendmode = theme->blendmode;
+       *vmpartspawner.particle_orientation = theme->orientation;
+       vmpartspawner.particle_color1[0] = (theme->color1 >> 16) & 0xFF; // VorteX: int only can store 0-255, not 0-256 which means 0 - 0,99609375...
+       vmpartspawner.particle_color1[1] = (theme->color1 >> 8) & 0xFF;
+       vmpartspawner.particle_color1[2] = (theme->color1 >> 0) & 0xFF;
+       vmpartspawner.particle_color2[0] = (theme->color2 >> 16) & 0xFF;
+       vmpartspawner.particle_color2[1] = (theme->color2 >> 8) & 0xFF;
+       vmpartspawner.particle_color2[2] = (theme->color2 >> 0) & 0xFF;
+       *vmpartspawner.particle_tex = (float)theme->tex;
+       *vmpartspawner.particle_size = theme->size;
+       *vmpartspawner.particle_sizeincrease = theme->sizeincrease;
+       *vmpartspawner.particle_alpha = (float)theme->alpha/256;
+       *vmpartspawner.particle_alphafade = (float)theme->alphafade/256;
+       *vmpartspawner.particle_time = theme->lifetime;
+       *vmpartspawner.particle_gravity = theme->gravity;
+       *vmpartspawner.particle_bounce = theme->bounce;
+       *vmpartspawner.particle_airfriction = theme->airfriction;
+       *vmpartspawner.particle_liquidfriction = theme->liquidfriction;
+       *vmpartspawner.particle_originjitter = theme->originjitter;
+       *vmpartspawner.particle_velocityjitter = theme->velocityjitter;
+       *vmpartspawner.particle_qualityreduction = theme->qualityreduction;
+       *vmpartspawner.particle_stretch = theme->stretch;
+       vmpartspawner.particle_staincolor1[0] = (theme->staincolor1 >> 16) & 0xFF;
+       vmpartspawner.particle_staincolor1[1] = (theme->staincolor1 >> 8) & 0xFF;
+       vmpartspawner.particle_staincolor1[2] = (theme->staincolor1 >> 0) & 0xFF;
+       vmpartspawner.particle_staincolor2[0] = (theme->staincolor2 >> 16) & 0xFF;
+       vmpartspawner.particle_staincolor2[1] = (theme->staincolor2 >> 8) & 0xFF;
+       vmpartspawner.particle_staincolor2[2] = (theme->staincolor2 >> 0) & 0xFF;
+       *vmpartspawner.particle_staintex = (float)theme->staintex;
+       *vmpartspawner.particle_delayspawn = theme->delayspawn;
+       *vmpartspawner.particle_delaycollision = theme->delaycollision;
+}
+
+// QC globals ->  particle theme
+void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme)
+{
+       theme->typeindex = (unsigned short)*vmpartspawner.particle_type;
+       theme->blendmode = (pblend_t)*vmpartspawner.particle_blendmode;
+       theme->orientation = (porientation_t)*vmpartspawner.particle_orientation;
+       theme->color1 = ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]);
+       theme->color2 = ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]);
+       theme->tex = (int)*vmpartspawner.particle_tex;
+       theme->size = *vmpartspawner.particle_size;
+       theme->sizeincrease = *vmpartspawner.particle_sizeincrease;
+       theme->alpha = (int)(*vmpartspawner.particle_alpha*256);
+       theme->alphafade = (int)(*vmpartspawner.particle_alphafade*256);
+       theme->lifetime = *vmpartspawner.particle_time;
+       theme->gravity = *vmpartspawner.particle_gravity;
+       theme->bounce = *vmpartspawner.particle_bounce;
+       theme->airfriction = *vmpartspawner.particle_airfriction;
+       theme->liquidfriction = *vmpartspawner.particle_liquidfriction;
+       theme->originjitter = *vmpartspawner.particle_originjitter;
+       theme->velocityjitter = *vmpartspawner.particle_velocityjitter;
+       theme->qualityreduction = (*vmpartspawner.particle_qualityreduction) ? true : false;
+       theme->stretch = *vmpartspawner.particle_stretch;
+       theme->staincolor1 = vmpartspawner.particle_staincolor1[0]*65536 + vmpartspawner.particle_staincolor1[1]*256 + vmpartspawner.particle_staincolor1[2];
+       theme->staincolor2 = vmpartspawner.particle_staincolor2[0]*65536 + vmpartspawner.particle_staincolor2[1]*256 + vmpartspawner.particle_staincolor2[2];
+       theme->staintex =(int)*vmpartspawner.particle_staintex;
+       theme->delayspawn = *vmpartspawner.particle_delayspawn;
+       theme->delaycollision = *vmpartspawner.particle_delaycollision;
+}
+
+// init particle spawner interface
+// # float(float max_themes) initparticlespawner
+void VM_CL_InitParticleSpawner (void)
+{
+       VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner);
+       VM_InitParticleSpawner((int)PRVM_G_FLOAT(OFS_PARM0));
+       vmpartspawner.themes[0].initialized = true;
+       VM_ResetParticleTheme(&vmpartspawner.themes[0]);
+       PRVM_G_FLOAT(OFS_RETURN) = (vmpartspawner.verified == true) ? 1 : 0;
+}
+
+// void() resetparticle
+void VM_CL_ResetParticle (void)
+{
+       VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle);
+       if (vmpartspawner.verified == false)
+       {
+               VM_Warning("VM_CL_ResetParticle: particle spawner not initialized\n");
+               return;
+       }
+       VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+}
+
+// void(float themenum) particletheme
+void VM_CL_ParticleTheme (void)
+{
+       int themenum;
+
+       VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme);
+       if (vmpartspawner.verified == false)
+       {
+               VM_Warning("VM_CL_ParticleTheme: particle spawner not initialized\n");
+               return;
+       }
+       themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+       if (themenum < 0 || themenum >= vmpartspawner.max_themes)
+       {
+               VM_Warning("VM_CL_ParticleTheme: bad theme number %i\n", themenum);
+               VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+               return;
+       }
+       if (vmpartspawner.themes[themenum].initialized == false)
+       {
+               VM_Warning("VM_CL_ParticleTheme: theme #%i not exists\n", themenum);
+               VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+               return;
+       }
+       // load particle theme into globals
+       VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[themenum]);
+}
+
+// float() saveparticletheme
+// void(float themenum) updateparticletheme
+void VM_CL_ParticleThemeSave (void)
+{
+       int themenum;
+
+       VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave);
+       if (vmpartspawner.verified == false)
+       {
+               VM_Warning("VM_CL_ParticleThemeSave: particle spawner not initialized\n");
+               return;
+       }
+       // allocate new theme, save it and return
+       if (prog->argc < 1)
+       {
+               for (themenum = 0; themenum < vmpartspawner.max_themes; themenum++)
+                       if (vmpartspawner.themes[themenum].initialized == false)
+                               break;
+               if (themenum >= vmpartspawner.max_themes)
+               {
+                       if (vmpartspawner.max_themes == 2048)
+                               VM_Warning("VM_CL_ParticleThemeSave: no free theme slots\n");
+                       else
+                               VM_Warning("VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n");
+                       PRVM_G_FLOAT(OFS_RETURN) = -1;
+                       return;
+               }
+               vmpartspawner.themes[themenum].initialized = true;
+               VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]);
+               PRVM_G_FLOAT(OFS_RETURN) = themenum;
+               return;
+       }
+       // update existing theme
+       themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+       if (themenum < 0 || themenum >= vmpartspawner.max_themes)
+       {
+               VM_Warning("VM_CL_ParticleThemeSave: bad theme number %i\n", themenum);
+               return;
+       }
+       vmpartspawner.themes[themenum].initialized = true;
+       VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]);
+}
+
+// void(float themenum) freeparticletheme
+void VM_CL_ParticleThemeFree (void)
+{
+       int themenum;
+
+       VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree);
+       if (vmpartspawner.verified == false)
+       {
+               VM_Warning("VM_CL_ParticleThemeFree: particle spawner not initialized\n");
+               return;
+       }
+       themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+       // check parms
+       if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+       {
+               VM_Warning("VM_CL_ParticleThemeFree: bad theme number %i\n", themenum);
+               return;
+       }
+       if (vmpartspawner.themes[themenum].initialized == false)
+       {
+               VM_Warning("VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum);
+               VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+               return;
+       }
+       // free theme
+       VM_ResetParticleTheme(&vmpartspawner.themes[themenum]);
+       vmpartspawner.themes[themenum].initialized = false;
+}
+
+// float(vector org, vector dir, [float theme]) particle
+// returns 0 if failed, 1 if succesful
+void VM_CL_SpawnParticle (void)
+{
+       float *org, *dir;
+       vmparticletheme_t *theme;
+       particle_t *part;
+       int themenum;
+
+       VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle2);
+       if (vmpartspawner.verified == false)
+       {
+               VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+               PRVM_G_FLOAT(OFS_RETURN) = 0; 
+               return;
+       }
+       org = PRVM_G_VECTOR(OFS_PARM0);
+       dir = PRVM_G_VECTOR(OFS_PARM1);
+       
+       if (prog->argc < 3) // global-set particle
+       {
+               part = CL_NewParticle((unsigned short)*vmpartspawner.particle_type, ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, (int)(*vmpartspawner.particle_alpha*256), (int)(*vmpartspawner.particle_alphafade*256), *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, ((int)vmpartspawner.particle_staincolor1[0] << 16) + ((int)vmpartspawner.particle_staincolor1[1] << 8) + ((int)vmpartspawner.particle_staincolor1[2]), ((int)vmpartspawner.particle_staincolor2[0] << 16) + ((int)vmpartspawner.particle_staincolor2[1] << 8) + ((int)vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex);
+               if (!part)
+               {
+                       PRVM_G_FLOAT(OFS_RETURN) = 0; 
+                       return;
+               }
+               if (*vmpartspawner.particle_delayspawn)
+                       part->delayedspawn = cl.time + *vmpartspawner.particle_delayspawn;
+               if (*vmpartspawner.particle_delaycollision)
+                       part->delayedcollisions = cl.time + *vmpartspawner.particle_delaycollision;
+       }
+       else // quick themed particle
+       {
+               themenum = (int)PRVM_G_FLOAT(OFS_PARM2);
+               if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+               {
+                       VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+                       PRVM_G_FLOAT(OFS_RETURN) = 0; 
+                       return;
+               }
+               theme = &vmpartspawner.themes[themenum];
+               part = CL_NewParticle(theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex);
+               if (!part)
+               {
+                       PRVM_G_FLOAT(OFS_RETURN) = 0; 
+                       return;
+               }
+               if (theme->delayspawn)
+                       part->delayedspawn = cl.time + theme->delayspawn;
+               if (theme->delaycollision)
+                       part->delayedcollisions = cl.time + theme->delaycollision;
+       }
+       PRVM_G_FLOAT(OFS_RETURN) = 1; 
+}
+
+// float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle
+// returns 0 if failed, 1 if success
+void VM_CL_SpawnParticleDelayed (void)
+{
+       float *org, *dir;
+       vmparticletheme_t *theme;
+       particle_t *part;
+       int themenum;
+
+       VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticle2);
+       if (vmpartspawner.verified == false)
+       {
+               VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+               PRVM_G_FLOAT(OFS_RETURN) = 0; 
+               return;
+       }
+       org = PRVM_G_VECTOR(OFS_PARM0);
+       dir = PRVM_G_VECTOR(OFS_PARM1);
+       if (prog->argc < 5) // global-set particle
+               part = CL_NewParticle((unsigned short)*vmpartspawner.particle_type, ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, (int)(*vmpartspawner.particle_alpha*256), (int)(*vmpartspawner.particle_alphafade*256), *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, ((int)vmpartspawner.particle_staincolor1[0] << 16) + ((int)vmpartspawner.particle_staincolor1[1] << 8) + ((int)vmpartspawner.particle_staincolor1[2]), ((int)vmpartspawner.particle_staincolor2[0] << 16) + ((int)vmpartspawner.particle_staincolor2[1] << 8) + ((int)vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex);
+       else // themed particle
+       {
+               themenum = (int)PRVM_G_FLOAT(OFS_PARM4);
+               if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+               {
+                       VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+                       PRVM_G_FLOAT(OFS_RETURN) = 0;  
+                       return;
+               }
+               theme = &vmpartspawner.themes[themenum];
+               part = CL_NewParticle(theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex);
+       }
+       if (!part) 
+       { 
+               PRVM_G_FLOAT(OFS_RETURN) = 0; 
+               return; 
+       }
+       part->delayedspawn = cl.time + PRVM_G_FLOAT(OFS_PARM2);
+       part->delayedcollisions = cl.time + PRVM_G_FLOAT(OFS_PARM3);
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+}
+
+//
 //====================
 //QC POLYGON functions
 //====================
@@ -2491,8 +2972,10 @@ vmpolygons_t vmpolygons[PRVM_MAXPROGS];
 // --blub
 void VM_CL_R_RenderScene (void)
 {
+       double t = Sys_DoubleTime();
        vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
        VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
+
        // we need to update any RENDER_VIEWMODEL entities at this point because
        // csqc supplies its own view matrix
        CL_UpdateViewEntities();
@@ -2501,6 +2984,9 @@ void VM_CL_R_RenderScene (void)
 
        polys->num_vertices = polys->num_triangles = 0;
        polys->progstarttime = prog->starttime;
+
+       // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
+       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
 }
 
 static void VM_ResizePolygons(vmpolygons_t *polys)
@@ -2601,7 +3087,8 @@ void VMPolygons_Store(vmpolygons_t *polys)
                mesh.texture = polys->begin_texture;
                mesh.num_vertices = polys->begin_vertices;
                mesh.num_triangles = polys->begin_vertices-2;
-               mesh.data_element3s = polygonelements;
+               mesh.data_element3i = polygonelement3i;
+               mesh.data_element3s = polygonelement3s;
                mesh.data_vertex3f = polys->begin_vertex[0];
                mesh.data_color4f = polys->begin_color[0];
                mesh.data_texcoord2f = polys->begin_texcoord[0];
@@ -2870,7 +3357,7 @@ realcheck:
        start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
        start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
        stop[2] = start[2] - 2*sv_stepheight.value;
-       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
+       trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
 
        if (trace.fraction == 1.0)
                return false;
@@ -2883,7 +3370,7 @@ realcheck:
                        start[0] = stop[0] = x ? maxs[0] : mins[0];
                        start[1] = stop[1] = y ? maxs[1] : mins[1];
 
-                       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
+                       trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
 
                        if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
                                bottom = trace.endpos[2];
@@ -2932,7 +3419,7 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
                                if (dz < 30)
                                        neworg[2] += 8;
                        }
-                       trace = CL_Move (ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+                       trace = CL_TraceBox(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
                        if (settrace)
                                CL_VM_SetTraceGlobals(&trace, svent);
 
@@ -2960,14 +3447,14 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        VectorCopy (neworg, end);
        end[2] -= sv_stepheight.value*2;
 
-       trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+       trace = CL_TraceBox(neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
        if (settrace)
                CL_VM_SetTraceGlobals(&trace, svent);
 
        if (trace.startsolid)
        {
                neworg[2] -= sv_stepheight.value;
-               trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+               trace = CL_TraceBox(neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
                if (settrace)
                        CL_VM_SetTraceGlobals(&trace, svent);
                if (trace.startsolid)
@@ -3692,16 +4179,16 @@ VM_buf_cvarlist,                                                // #517 void(float buf, string prefix, string antiprefix)
 VM_cvar_description,                                   // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
 VM_gettime,                                            // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
 VM_keynumtostring,                             // #520 string keynumtostring(float keynum)
-VM_findkeysforcommand,         // #521 string findkeysforcommand(string command)
-NULL,                                                  // #522
-NULL,                                                  // #523
-NULL,                                                  // #524
-NULL,                                                  // #525
-NULL,                                                  // #526
-NULL,                                                  // #527
-NULL,                                                  // #528
-NULL,                                                  // #529
-NULL,                                                  // #530
+VM_findkeysforcommand,                 // #521 string findkeysforcommand(string command)
+VM_CL_InitParticleSpawner,             // #522 void(float max_themes) initparticlespawner (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ResetParticle,                   // #523 void() resetparticle (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ParticleTheme,                   // #524 void(float theme) particletheme (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ParticleThemeSave,               // #525 void() particlethemesave, void(float theme) particlethemeupdate (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ParticleThemeFree,               // #526 void() particlethemefree (DP_CSQC_SPAWNPARTICLE)
+VM_CL_SpawnParticle,                   // #527 float(vector org, vector vel, [float theme]) particle (DP_CSQC_SPAWNPARTICLE)
+VM_CL_SpawnParticleDelayed,            // #528 float(vector org, vector vel, float delay, float collisiondelay, [float theme]) delayedparticle (DP_CSQC_SPAWNPARTICLE)
+VM_loadfromdata,                               // #529
+VM_loadfromfile,                               // #530
 NULL,                                                  // #531
 NULL,                                                  // #532
 NULL,                                                  // #533
@@ -3776,15 +4263,15 @@ NULL,                                                   // #601
 NULL,                                                  // #602
 NULL,                                                  // #603
 NULL,                                                  // #604
-NULL,                                                  // #605
-NULL,                                                  // #606
-NULL,                                                  // #607
+VM_callfunction,                               // #605
+VM_writetofile,                                        // #606
+VM_isfunction,                                 // #607
 NULL,                                                  // #608
 NULL,                                                  // #609
 NULL,                                                  // #610
 NULL,                                                  // #611
 NULL,                                                  // #612
-NULL,                                                  // #613
+VM_parseentitydata,                            // #613
 NULL,                                                  // #614
 NULL,                                                  // #615
 NULL,                                                  // #616
@@ -3821,6 +4308,7 @@ void VM_CL_Cmd_Init(void)
 
 void VM_CL_Cmd_Reset(void)
 {
+       World_End(&cl.world);
        VM_Cmd_Reset();
        VM_Polygons_Reset();
 }