]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - clvm_cmds.c
added particle effect scripting using effectinfo.txt, this means configurable effects...
[xonotic/darkplaces.git] / clvm_cmds.c
index 7b3900a6c2b1023a3e653aa017e71f5fb4d70ebf..7a2613b6b37629c870a397cc0221ee9e56c1b46d 100644 (file)
@@ -441,11 +441,11 @@ void VM_CL_lightstyle (void)
 
        i = PRVM_G_FLOAT(OFS_PARM0);
        c = PRVM_G_STRING(OFS_PARM1);
-       if (i >= cl_max_lightstyle)
+       if (i >= cl.max_lightstyle)
                PF_WARNING("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
-       strlcpy (cl_lightstyle[i].map,  MSG_ReadString(), sizeof (cl_lightstyle[i].map));
-       cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
-       cl_lightstyle[i].length = (int)strlen(cl_lightstyle[i].map);
+       strlcpy (cl.lightstyle[i].map,  MSG_ReadString(), sizeof (cl.lightstyle[i].map));
+       cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
+       cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
 }
 
 // #40 float(entity e) checkbottom
@@ -474,7 +474,7 @@ void VM_CL_checkbottom (void)
                {
                        start[0] = x ? maxs[0] : mins[0];
                        start[1] = y ? maxs[1] : mins[1];
-                       if (!(CL_PointSuperContents(start) & SUPERCONTENTS_SOLID))
+                       if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
                                goto realcheck;
                }
 
@@ -538,22 +538,7 @@ void VM_CL_particle (void)
        dir = PRVM_G_VECTOR(OFS_PARM1);
        color = PRVM_G_FLOAT(OFS_PARM2);
        count = PRVM_G_FLOAT(OFS_PARM3);
-       if (cl_particles_blood_bloodhack.integer)
-       {
-               if (color == 73)
-               {
-                       // regular blood
-                       CL_BloodPuff(org, dir, count / 2);
-                       return;
-               }
-               if (color == 225)
-               {
-                       // lightning blood
-                       CL_BloodPuff(org, dir, count / 2);
-                       return;
-               }
-       }
-       CL_RunParticleEffect (org, dir, color, count);
+       CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
 }
 
 // #49 void(entity ent, float ideal_yaw, float speed_yaw) ChangeYaw
@@ -741,62 +726,6 @@ matrix4x4_t csqc_listenermatrix;
 qboolean csqc_usecsqclistener = false, csqc_frame = false;//[515]: per-frame
 qboolean csqc_onground;
 
-static char *particleeffect_names[] =
-{
-       "TE_SPIKE",
-       "TE_SUPERSPIKE",
-       "TE_GUNSHOT",
-       "TE_EXPLOSION",
-       "TE_TAREXPLOSION",
-       "TE_LIGHTNING1",//trail
-       "TE_LIGHTNING2",//trail
-       "TE_WIZSPIKE",
-       "TE_KNIGHTSPIKE",
-       "TE_LIGHTNING3",//trail
-       "TE_LAVASPLASH",
-       "TE_TELEPORT",
-       "TE_EXPLOSION2",
-       "TE_BEAM",//trail
-       "TE_EXPLOSION3",
-       "",//TE_LIGHTNING4NEH
-       "TE_BLOOD",
-       "TE_SPARK",
-       "",//TE_BLOODSHOWER
-       "TE_EXPLOSIONRGB",
-       "",//unused
-       "",
-       "",
-       "TE_GUNSHOTQUAD",
-       "TE_SPIKEQUAD",
-       "TE_SUPERSPIKEQUAD",
-       "TE_EXPLOSIONQUAD",
-       "",
-       "",
-       "",
-       "TE_FLAMEJET",
-       "TE_PLASMABURN",
-       "TE_TEI_G3",
-       "TE_TEI_SMOKE",
-       "TE_TEI_BIGEXPLOSION",
-       "TE_TEI_PLASMAHIT",
-
-
-       //trail effects (as modelflags)
-       "EF_ROCKET",
-       "EF_GRENADE",
-       "EF_GIB",
-       "EF_TRACER",
-       "EF_ZOMGIB",
-       "EF_TRACER2",
-       "EF_TRACER3",
-       "EF_NEH_CIGAR",
-       "EF_NEXUIZ_PLASMA",
-       "EF_GLOWTRAIL",
-};
-
-#define CSQC_TRAILSTART 36
-static const int particleeffects_num = sizeof(particleeffect_names)/sizeof(char*);
-
 static void CSQC_R_RecalcView (void)
 {
        extern matrix4x4_t viewmodelmatrix;
@@ -1095,13 +1024,10 @@ void VM_CL_particleeffectnum (void)
        int                     i;
        VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
        n = PRVM_G_STRING(OFS_PARM0);
-       for(i=0;i<particleeffects_num;i++)
-               if(!strcasecmp(particleeffect_names[i], n))
-               {
-                       PRVM_G_FLOAT(OFS_RETURN) = i;
-                       return;
-               }
-       PRVM_G_FLOAT(OFS_RETURN) = -1;
+       i = CL_ParticleEffectIndexForName(n);
+       if (i == 0)
+               i = -1;
+       PRVM_G_FLOAT(OFS_RETURN) = i;
 }
 
 void CSQC_ParseBeam (int ent, vec3_t start, vec3_t end, model_t *m, int lightning)
@@ -1110,13 +1036,13 @@ void CSQC_ParseBeam (int ent, vec3_t start, vec3_t end, model_t *m, int lightnin
        beam_t  *b;
 
        // override any beam with the same entity
-       for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
+       for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++)
        {
                if (b->entity == ent && ent)
                {
                        //b->entity = ent;
                        b->lightning = lightning;
-                       b->relativestartvalid = (ent && cl_csqcentities[ent].state_current.active) ? 2 : 0;
+                       b->relativestartvalid = (ent && cl.csqcentities[ent].state_current.active) ? 2 : 0;
                        b->model = m;
                        b->endtime = cl.time + 0.2;
                        VectorCopy (start, b->start);
@@ -1126,13 +1052,13 @@ void CSQC_ParseBeam (int ent, vec3_t start, vec3_t end, model_t *m, int lightnin
        }
 
        // find a free beam
-       for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
+       for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++)
        {
                if (!b->model || b->endtime < cl.time)
                {
                        b->entity = ent;
                        b->lightning = lightning;
-                       b->relativestartvalid = (ent && cl_csqcentities[ent].state_current.active) ? 2 : 0;
+                       b->relativestartvalid = (ent && cl.csqcentities[ent].state_current.active) ? 2 : 0;
                        b->model = m;
                        b->endtime = cl.time + 0.2;
                        VectorCopy (start, b->start);
@@ -1146,142 +1072,39 @@ void CSQC_ParseBeam (int ent, vec3_t start, vec3_t end, model_t *m, int lightnin
 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
 void VM_CL_trailparticles (void)
 {
-       int                             i, entnum, col;
+       int                             i, entnum;
        float                   *start, *end;
-       entity_t                *ent;
+       prvm_edict_t    *t;
        VM_SAFEPARMCOUNT(4, VM_CL_trailparticles);
 
-       entnum  = PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0));
+       t = PRVM_G_EDICT(OFS_PARM0);
+       entnum  = PRVM_NUM_FOR_EDICT(t);
        i               = PRVM_G_FLOAT(OFS_PARM1);
        start   = PRVM_G_VECTOR(OFS_PARM2);
        end             = PRVM_G_VECTOR(OFS_PARM3);
 
-       if(i >= particleeffects_num)
-               return;
        if (entnum >= MAX_EDICTS)
        {
                Con_Printf("CSQC_ParseBeam: invalid entity number %i\n", entnum);
                return;
        }
-       if (entnum >= cl_max_csqcentities)
+       if (entnum >= cl.max_csqcentities)
                CL_ExpandCSQCEntities(entnum);
 
-       ent = &cl_csqcentities[entnum];
-
-       if(prog->argc > 4)
-               col = PRVM_G_FLOAT(OFS_PARM4);
-       else
-               col = ent->state_current.glowcolor;
-
-       switch(i)
-       {
-       case TE_LIGHTNING1:
-               CSQC_ParseBeam(entnum, start, end, cl.model_bolt, true);
-               break;
-       case TE_LIGHTNING2:
-               CSQC_ParseBeam(entnum, start, end, cl.model_bolt2, true);
-               break;
-       case TE_LIGHTNING3:
-               CSQC_ParseBeam(entnum, start, end, cl.model_bolt3, false);
-               break;
-       case TE_BEAM:
-               CSQC_ParseBeam(entnum, start, end, cl.model_beam, false);
-               break;
-       default:
-               CL_RocketTrail(start, end, i-CSQC_TRAILSTART, col, ent);
-               break;
-       }
+       CL_ParticleEffect(i, VectorDistance(start, end), start, end, t->fields.client->velocity, t->fields.client->velocity, &cl.csqcentities[entnum], PRVM_G_FLOAT(OFS_PARM4));
 }
 
-//#337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
+//#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
 void VM_CL_pointparticles (void)
 {
        int                     i, n;
        float           *f, *v;
-       if(prog->argc < 2)
-               VM_SAFEPARMCOUNT(2, VM_CL_pointparticles);
+       VM_SAFEPARMCOUNT(4, VM_CL_pointparticles);
        i = PRVM_G_FLOAT(OFS_PARM0);
        f = PRVM_G_VECTOR(OFS_PARM1);
-       if(prog->argc >= 4)
-       {
-               v = PRVM_G_VECTOR(OFS_PARM2);
-               n = PRVM_G_FLOAT(OFS_PARM3);
-       }
-       else
-       {
-               v = vec3_origin;
-               n = 15;
-       }
-
-       if(i >= particleeffects_num)
-               return;
-
-       switch(i)
-       {
-       case TE_SPIKE:
-       case TE_SPIKEQUAD:
-       case TE_GUNSHOT:
-       case TE_GUNSHOTQUAD:
-               CL_SparkShower(f, v, 15, 1, 0);
-               CL_Smoke(f, v, 15, 0);
-               if (cl_particles_bulletimpacts.integer)
-                       CL_BulletMark(f);
-               break;
-       case TE_SUPERSPIKE:
-       case TE_SUPERSPIKEQUAD:
-               CL_SparkShower(f, v, 30, 1, 0);
-               CL_Smoke(f, v, 30, 0);
-               if (cl_particles_bulletimpacts.integer)
-                       CL_BulletMark(f);
-               break;
-       case TE_EXPLOSION:
-       case TE_EXPLOSIONQUAD:
-       case TE_TEI_BIGEXPLOSION:
-               CL_ParticleExplosion(f);
-               break;
-       case TE_TAREXPLOSION:
-               CL_BlobExplosion(f);
-               break;
-       case TE_WIZSPIKE:
-               CL_RunParticleEffect(f, v, 20, 30);
-               break;
-       case TE_KNIGHTSPIKE:
-               CL_RunParticleEffect(f, v, 226, 20);
-               break;
-       case TE_LAVASPLASH:
-               CL_LavaSplash(f);
-               break;
-       case TE_TELEPORT:
-               CL_TeleportSplash(f);
-               break;
-       case TE_EXPLOSION2:
-       case TE_EXPLOSION3:
-       case TE_EXPLOSIONRGB:
-               CL_ParticleExplosion2(f, v[0], v[1]);
-               break;
-       case TE_BLOOD:
-               CL_BloodPuff(f, v, n);
-               break;
-       case TE_SPARK:
-               CL_SparkShower(f, v, n, 1, 0);
-               break;
-       case TE_FLAMEJET:
-               CL_Flames(f, v, n);
-               break;
-       case TE_PLASMABURN:
-               CL_PlasmaBurn(f);
-               break;
-       case TE_TEI_G3:
-               CL_BeamParticle(f, v, 8, 1, 1, 1, 1, 1);
-               break;
-       case TE_TEI_SMOKE:
-               CL_Tei_Smoke(f, v, n);
-               break;
-       case TE_TEI_PLASMAHIT:
-               CL_Tei_PlasmaHit(f, v, n);
-               break;
-       default:break;
-       }
+       v = PRVM_G_VECTOR(OFS_PARM2);
+       n = PRVM_G_FLOAT(OFS_PARM3);
+       CL_ParticleEffect(i, n, f, f, v, v, NULL, 0);
 }
 
 //#338 void(string s) cprint (EXT_CSQC)
@@ -1327,13 +1150,13 @@ void VM_CL_getinputstate (void)
                        prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
                        if(cl.movement_queue[i].crouch)
                        {
-                               VectorCopy(cl_playercrouchmins, prog->globals.client->pmove_mins);
-                               VectorCopy(cl_playercrouchmaxs, prog->globals.client->pmove_maxs);
+                               VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
+                               VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
                        }
                        else
                        {
-                               VectorCopy(cl_playerstandmins, prog->globals.client->pmove_mins);
-                               VectorCopy(cl_playerstandmaxs, prog->globals.client->pmove_maxs);
+                               VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
+                               VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
                        }
                }
 }
@@ -1525,16 +1348,25 @@ void VM_CL_te_blood (void)
                return;
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       CL_BloodPuff(pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
+       CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
 }
 
 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
 void VM_CL_te_bloodshower (void)
 {
+       vec_t speed;
+       vec3_t vel1, vel2;
        VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
                return;
-       CL_BloodShower(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3));
+       speed = PRVM_G_FLOAT(OFS_PARM2);
+       vel1[0] = -speed;
+       vel1[1] = -speed;
+       vel1[2] = -speed;
+       vel2[0] = speed;
+       vel2[1] = speed;
+       vel2[2] = speed;
+       CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
 }
 
 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
@@ -1555,8 +1387,6 @@ void VM_CL_te_explosionrgb (void)
 void VM_CL_te_particlecube (void)
 {
        VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
-       if (PRVM_G_FLOAT(OFS_PARM3) < 1)
-               return;
        CL_ParticleCube(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4), PRVM_G_FLOAT(OFS_PARM5), PRVM_G_FLOAT(OFS_PARM6));
 }
 
@@ -1564,8 +1394,6 @@ void VM_CL_te_particlecube (void)
 void VM_CL_te_particlerain (void)
 {
        VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
-       if (PRVM_G_FLOAT(OFS_PARM3) < 1)
-               return;
        CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4), 0);
 }
 
@@ -1573,8 +1401,6 @@ void VM_CL_te_particlerain (void)
 void VM_CL_te_particlesnow (void)
 {
        VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
-       if (PRVM_G_FLOAT(OFS_PARM3) < 1)
-               return;
        CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4), 1);
 }
 
@@ -1585,11 +1411,9 @@ void VM_CL_te_spark (void)
        vec3_t          pos2;
        VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
 
-       if (PRVM_G_FLOAT(OFS_PARM2) < 1)
-               return;
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       CL_SparkShower(pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2), 1, 0);
+       CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
 }
 
 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
@@ -1597,16 +1421,11 @@ void VM_CL_te_gunshotquad (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       CL_SparkShower(pos2, vec3_origin, 15, 1, 0);
-       CL_Smoke(pos2, vec3_origin, 15, 0);
-       CL_BulletMark(pos2);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
 }
 
 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
@@ -1614,20 +1433,12 @@ void VM_CL_te_spikequad (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        int                     rnd;
        VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       if (cl_particles_bulletimpacts.integer)
-       {
-               CL_SparkShower(pos2, vec3_origin, 15, 1, 0);
-               CL_Smoke(pos2, vec3_origin, 15, 0);
-               CL_BulletMark(pos2);
-       }
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
        else
        {
@@ -1643,20 +1454,12 @@ void VM_CL_te_superspikequad (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        int                     rnd;
        VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       if (cl_particles_bulletimpacts.integer)
-       {
-               CL_SparkShower(pos2, vec3_origin, 30, 1, 0);
-               CL_Smoke(pos2, vec3_origin, 30, 0);
-               CL_BulletMark(pos2);
-       }
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
        else
        {
@@ -1672,14 +1475,11 @@ void VM_CL_te_explosionquad (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 10);
-       CL_ParticleExplosion(pos2);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
 }
 
@@ -1688,13 +1488,11 @@ void VM_CL_te_smallflash (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 10);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
 }
 
 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
@@ -1720,9 +1518,7 @@ void VM_CL_te_gunshot (void)
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       CL_SparkShower(pos2, vec3_origin, 15, 1, 0);
-       CL_Smoke(pos2, vec3_origin, 15, 0);
-       CL_BulletMark(pos2);
+       CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
 }
 
 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
@@ -1735,12 +1531,7 @@ void VM_CL_te_spike (void)
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       if (cl_particles_bulletimpacts.integer)
-       {
-               CL_SparkShower(pos2, vec3_origin, 15, 1, 0);
-               CL_Smoke(pos2, vec3_origin, 15, 0);
-               CL_BulletMark(pos2);
-       }
+       CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
        else
        {
@@ -1761,12 +1552,7 @@ void VM_CL_te_superspike (void)
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       if (cl_particles_bulletimpacts.integer)
-       {
-               CL_SparkShower(pos2, vec3_origin, 30, 1, 0);
-               CL_Smoke(pos2, vec3_origin, 30, 0);
-               CL_BulletMark(pos2);
-       }
+       CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
        else
        {
@@ -1782,14 +1568,11 @@ void VM_CL_te_explosion (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 10);
-       CL_ParticleExplosion(pos2);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
 }
 
@@ -1798,14 +1581,11 @@ void VM_CL_te_tarexplosion (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 10);
-       CL_BlobExplosion(pos2);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
 }
 
@@ -1814,14 +1594,11 @@ void VM_CL_te_wizspike (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, -1, false, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-       CL_RunParticleEffect(pos2, vec3_origin, 20, 30);
+       CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
 }
 
@@ -1830,14 +1607,11 @@ void VM_CL_te_knightspike (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, -1, false, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-       CL_RunParticleEffect(pos2, vec3_origin, 226, 20);
+       CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
        S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
 }
 
@@ -1845,20 +1619,14 @@ void VM_CL_te_knightspike (void)
 void VM_CL_te_lavasplash (void)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
-       CL_LavaSplash(PRVM_G_VECTOR(OFS_PARM0));
+       CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
 }
 
 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
 void VM_CL_te_teleport (void)
 {
-       float           *pos;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
-
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 200, 1.0f, 1.0f, 1.0f, 600, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-       CL_TeleportSplash(pos);
+       CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
 }
 
 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
@@ -1890,20 +1658,18 @@ static void VM_CL_NewBeam (int ent, float *start, float *end, model_t *m, qboole
 {
        beam_t  *b;
        int             i;
-       extern entity_t *cl_csqcentities;
-       extern int cl_max_csqcentities;
 
-       if (ent >= cl_max_csqcentities)
+       if (ent >= cl.max_csqcentities)
                CL_ExpandCSQCEntities(ent);
 
        // override any beam with the same entity
-       for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
+       for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++)
        {
                if (b->entity == ent && ent)
                {
                        //b->entity = ent;
                        b->lightning = lightning;
-                       b->relativestartvalid = (ent && cl_csqcentities[ent].state_current.active) ? 2 : 0;
+                       b->relativestartvalid = (ent && cl.csqcentities[ent].state_current.active) ? 2 : 0;
                        b->model = m;
                        b->endtime = cl.time + 0.2;
                        VectorCopy (start, b->start);
@@ -1913,13 +1679,13 @@ static void VM_CL_NewBeam (int ent, float *start, float *end, model_t *m, qboole
        }
 
        // find a free beam
-       for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
+       for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++)
        {
                if (!b->model || b->endtime < cl.time)
                {
                        b->entity = ent;
                        b->lightning = lightning;
-                       b->relativestartvalid = (ent && cl_csqcentities[ent].state_current.active) ? 2 : 0;
+                       b->relativestartvalid = (ent && cl.csqcentities[ent].state_current.active) ? 2 : 0;
                        b->model = m;
                        b->endtime = cl.time + 0.2;
                        VectorCopy (start, b->start);
@@ -1963,14 +1729,11 @@ void VM_CL_te_plasmaburn (void)
 {
        float           *pos;
        vec3_t          pos2;
-       matrix4x4_t     tempmatrix;
        VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
 
        pos = PRVM_G_VECTOR(OFS_PARM0);
        CL_FindNonSolidLocation(pos, pos2, 4);
-       Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
-       CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
-       CL_PlasmaBurn(pos2);
+       CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
 }
 
 
@@ -1978,7 +1741,7 @@ void VM_CL_te_plasmaburn (void)
 //DP_QC_GETSURFACE
 
 void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out);
-static msurface_t *cl_getsurface(prvm_edict_t *ed, int surfacenum)
+static model_t *cl_getmodel(prvm_edict_t *ed)
 {
        int modelindex;
        model_t *model = NULL;
@@ -1998,8 +1761,11 @@ static msurface_t *cl_getsurface(prvm_edict_t *ed, int surfacenum)
                if(modelindex < MAX_MODELS)
                        model = cl.model_precache[modelindex];
        }
-       if(!model)
-               return NULL;
+       return model;
+}
+
+static msurface_t *cl_getsurface(model_t *model, int surfacenum)
+{
        if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
                return NULL;
        return model->data_surfaces + surfacenum + model->firstmodelsurface;
@@ -2008,9 +1774,10 @@ static msurface_t *cl_getsurface(prvm_edict_t *ed, int surfacenum)
 // #434 float(entity e, float s) getsurfacenumpoints
 void VM_CL_getsurfacenumpoints(void)
 {
+       model_t *model = cl_getmodel(PRVM_G_EDICT(OFS_PARM0));
        msurface_t *surface;
        // return 0 if no such surface
-       if (!(surface = cl_getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
+       if (!model || !(surface = cl_getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
        {
                PRVM_G_FLOAT(OFS_RETURN) = 0;
                return;
@@ -2024,35 +1791,35 @@ void VM_CL_getsurfacenumpoints(void)
 void VM_CL_getsurfacepoint(void)
 {
        prvm_edict_t *ed;
+       model_t *model;
        msurface_t *surface;
        int pointnum;
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
        ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!ed || ed->priv.server->free)
-               return;
-       if (!(surface = cl_getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
+       if (!(model = cl_getmodel(ed)) || !(surface = cl_getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
                return;
        // note: this (incorrectly) assumes it is a simple polygon
        pointnum = PRVM_G_FLOAT(OFS_PARM2);
        if (pointnum < 0 || pointnum >= surface->num_vertices)
                return;
        // FIXME: implement rotation/scaling
-       VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
+       VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
 }
 
 // #436 vector(entity e, float s) getsurfacenormal
 void VM_CL_getsurfacenormal(void)
 {
+       model_t *model;
        msurface_t *surface;
        vec3_t normal;
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       if (!(surface = cl_getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
+       if (!(model = cl_getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
                return;
        // FIXME: implement rotation/scaling
        // note: this (incorrectly) assumes it is a simple polygon
        // note: this only returns the first triangle, so it doesn't work very
        // well for curved surfaces or arbitrary meshes
-       TriangleNormal((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 3, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
+       TriangleNormal((model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 3, (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
        VectorNormalize(normal);
        VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
 }
@@ -2060,9 +1827,10 @@ void VM_CL_getsurfacenormal(void)
 // #437 string(entity e, float s) getsurfacetexture
 void VM_CL_getsurfacetexture(void)
 {
+       model_t *model;
        msurface_t *surface;
        PRVM_G_INT(OFS_RETURN) = 0;
-       if (!(surface = cl_getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
+       if (!(model = cl_getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
                return;
        PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
 }
@@ -2070,7 +1838,7 @@ void VM_CL_getsurfacetexture(void)
 // #438 float(entity e, vector p) getsurfacenearpoint
 void VM_CL_getsurfacenearpoint(void)
 {
-       int surfacenum, best, modelindex;
+       int surfacenum, best;
        vec3_t clipped, p;
        vec_t dist, bestdist;
        prvm_edict_t *ed;
@@ -2079,28 +1847,11 @@ void VM_CL_getsurfacenearpoint(void)
        vec_t *point;
        PRVM_G_FLOAT(OFS_RETURN) = -1;
        ed = PRVM_G_EDICT(OFS_PARM0);
-       point = PRVM_G_VECTOR(OFS_PARM1);
-
-       if (!ed || ed->priv.server->free)
-               return;
-       modelindex = ed->fields.client->modelindex;
-       if(!modelindex)
-               return;
-       if(modelindex<0)
-       {
-               modelindex = -(modelindex+1);
-               if(modelindex < MAX_MODELS)
-                       model = cl.csqc_model_precache[modelindex];
-       }
-       else
-               if(modelindex < MAX_MODELS)
-                       model = cl.model_precache[modelindex];
-       if(!model)
-               return;
-       if (!model->num_surfaces)
+       if(!(model = cl_getmodel(ed)) || !model->num_surfaces)
                return;
 
        // FIXME: implement rotation/scaling
+       point = PRVM_G_VECTOR(OFS_PARM1);
        VectorSubtract(point, ed->fields.client->origin, p);
        best = -1;
        bestdist = 1000000000;
@@ -2133,13 +1884,12 @@ void VM_CL_getsurfacenearpoint(void)
 void VM_CL_getsurfaceclippedpoint(void)
 {
        prvm_edict_t *ed;
+       model_t *model;
        msurface_t *surface;
        vec3_t p, out;
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
        ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!ed || ed->priv.server->free)
-               return;
-       if (!(surface = cl_getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
+       if (!(model = cl_getmodel(ed)) || !(surface = cl_getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
                return;
        // FIXME: implement rotation/scaling
        VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
@@ -2601,16 +2351,16 @@ void VM_CL_selecttraceline (void)
        csqcents = PRVM_G_FLOAT(OFS_PARM3);
        ent = 0;
 
-       if((csqcents && ignore > cl_num_csqcentities) || (!csqcents && ignore > cl_num_entities))
+       if((csqcents && ignore > cl.num_csqcentities) || (!csqcents && ignore > cl.num_entities))
        {
                Con_Printf("VM_CL_selecttraceline: out of entities\n");
                return;
        }
        else
                if(csqcents)
-                       prog->globals.client->trace_fraction = CL_SelectTraceLine(v1, v2, prog->globals.client->trace_endpos, prog->globals.client->trace_plane_normal, &prog->globals.client->trace_ent, &cl_csqcentities[ignore].render, csqcents);
+                       prog->globals.client->trace_fraction = CL_SelectTraceLine(v1, v2, prog->globals.client->trace_endpos, prog->globals.client->trace_plane_normal, &prog->globals.client->trace_ent, &cl.csqcentities[ignore].render, csqcents);
                else
-                       prog->globals.client->trace_fraction = CL_SelectTraceLine(v1, v2, prog->globals.client->trace_endpos, prog->globals.client->trace_plane_normal, &ent, &cl_entities[ignore].render, csqcents);
+                       prog->globals.client->trace_fraction = CL_SelectTraceLine(v1, v2, prog->globals.client->trace_endpos, prog->globals.client->trace_plane_normal, &ent, &cl.entities[ignore].render, csqcents);
        PRVM_G_FLOAT(OFS_RETURN) = ent;
 }