#define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY)
#define CL_HitNetworkPlayers(move) !((move) == MOVE_WORLDONLY || (move) == MOVE_NOMONSTERS)
-// #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
+// #16 void(vector v1, vector v2, float movetype, entity ignore) traceline
static void VM_CL_traceline (void)
{
float *v1, *v2;
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);
}
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);
}
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)
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)
{
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);
}
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;
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];
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);
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)
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);
//#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;
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;
}
//============================================================================
VM_SAFEPARMCOUNT(1, VM_CL_unproject);
f = PRVM_G_VECTOR(OFS_PARM0);
if(v_flipped.integer)
- f[0] = r_refdef.view.x + r_refdef.view.width - f[0];
- VectorSet(temp, f[2], (-1.0 + 2.0 * (f[0] - r_refdef.view.x)) / r_refdef.view.width * f[2] * -r_refdef.view.frustum_x, (-1.0 + 2.0 * (f[1] - r_refdef.view.y)) / r_refdef.view.height * f[2] * -r_refdef.view.frustum_y);
+ f[0] = (2 * r_refdef.view.x + r_refdef.view.width) * (vid_conwidth.integer / (float) vid.width) - f[0];
+ VectorSet(temp,
+ f[2],
+ (-1.0 + 2.0 * (f[0] / (vid_conwidth.integer / (float) vid.width) - r_refdef.view.x) / r_refdef.view.width) * f[2] * -r_refdef.view.frustum_x,
+ (-1.0 + 2.0 * (f[1] / (vid_conheight.integer / (float) vid.height) - r_refdef.view.y) / r_refdef.view.height) * f[2] * -r_refdef.view.frustum_y);
Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
}
Matrix4x4_Transform(&m, f, v);
if(v_flipped.integer)
v[1] = -v[1];
- VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.x + r_refdef.view.width*0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x), r_refdef.view.y + r_refdef.view.height*0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y), v[0]);
+ VectorSet(PRVM_G_VECTOR(OFS_RETURN),
+ (vid_conwidth.integer / (float) vid.width) * (r_refdef.view.x + r_refdef.view.width*0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x)),
+ (vid_conheight.integer / (float) vid.height) * (r_refdef.view.y + r_refdef.view.height*0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y)),
+ v[0]);
}
//#330 float(float stnum) getstatf (EXT_CSQC)
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;
}
int i, frame;
VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
frame = (int)PRVM_G_FLOAT(OFS_PARM0);
+ PRVM_G_FLOAT(OFS_RETURN) = false;
for (i = 0;i < CL_MAX_USERCMDS;i++)
{
if (cl.movecmd[i].sequence == frame)
VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
}
+ PRVM_G_FLOAT(OFS_RETURN) = true;
}
}
}
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;
return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
else
return -1;
-};
+}
int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
{
{
prvm_eval_t *val;
float scale;
+ float pitchsign = 1;
+ dp_model_t *model;
scale = 1;
val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
if(viewmatrix)
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
- Matrix4x4_CreateFromQuakeEntity(out, 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], scale);
+ {
+ if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
+ pitchsign = -1;
+ 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);
+ }
}
//============================================================================
+//====================
+// 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
//====================
// --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();
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)
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;
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];
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);
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)
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
}
+/*
+=================
+VM_CL_checkpvs
+
+Checks if an entity is in a point's PVS.
+Should be fast but can be inexact.
+
+float checkpvs(vector viewpos, entity viewee) = #240;
+=================
+*/
+static void VM_CL_checkpvs (void)
+{
+ vec3_t viewpos;
+ prvm_edict_t *viewee;
+ vec3_t mi, ma;
+#if 1
+ unsigned char *pvs;
+#else
+ static int fatpvsbytes;
+ static unsigned char fatpvs[MAX_MAP_LEAFS/8];
+#endif
+
+ VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
+ VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
+ viewee = PRVM_G_EDICT(OFS_PARM1);
+
+ if(viewee->priv.required->free)
+ {
+ VM_Warning("checkpvs: can not check free entity\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 4;
+ return;
+ }
+
+ VectorAdd(viewee->fields.server->origin, viewee->fields.server->mins, mi);
+ VectorAdd(viewee->fields.server->origin, viewee->fields.server->maxs, ma);
+
+#if 1
+ if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
+ {
+ // no PVS support on this worldmodel... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 3;
+ return;
+ }
+ pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
+ if(!pvs)
+ {
+ // viewpos isn't in any PVS... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 2;
+ return;
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, mi, ma);
+#else
+ // using fat PVS like FTEQW does (slow)
+ if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
+ {
+ // no PVS support on this worldmodel... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 3;
+ return;
+ }
+ fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
+ if(!fatpvsbytes)
+ {
+ // viewpos isn't in any PVS... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 2;
+ return;
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, mi, ma);
+#endif
+}
//============================================================================
// To create a almost working builtin file from this replace:
VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
VM_CL_spawn, // #14 entity() spawn (QUAKE)
VM_remove, // #15 void(entity e) remove (QUAKE)
-VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
+VM_CL_traceline, // #16 void(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
NULL, // #17 entity() checkclient (QUAKE)
VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
NULL, // #237
NULL, // #238
NULL, // #239
-NULL, // #240
+VM_CL_checkpvs, // #240
NULL, // #241
NULL, // #242
NULL, // #243
VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
VM_stringwidth, // #327 // FIXME is this okay?
VM_drawsubpic, // #328 // FIXME is this okay?
-NULL, // #329
+VM_drawrotpic, // #329 // FIXME is this okay?
VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
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
+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)
NULL, // #529
NULL, // #530
-NULL, // #531
+NULL, // #531
NULL, // #532
+NULL, // #533
+NULL, // #534
+NULL, // #535
+NULL, // #536
+NULL, // #537
+NULL, // #538
+NULL, // #539
+NULL, // #540
+NULL, // #541
+NULL, // #542
+NULL, // #543
+NULL, // #544
+NULL, // #545
+NULL, // #546
+NULL, // #547
+NULL, // #548
+NULL, // #549
+NULL, // #550
+NULL, // #551
+NULL, // #552
+NULL, // #553
+NULL, // #554
+NULL, // #555
+NULL, // #556
+NULL, // #557
+NULL, // #558
+NULL, // #559
+NULL, // #560
+NULL, // #561
+NULL, // #562
+NULL, // #563
+NULL, // #564
+NULL, // #565
+NULL, // #566
+NULL, // #567
+NULL, // #568
+NULL, // #569
+NULL, // #570
+NULL, // #571
+NULL, // #572
+NULL, // #573
+NULL, // #574
+NULL, // #575
+NULL, // #576
+NULL, // #577
+NULL, // #578
+NULL, // #579
+NULL, // #580
+NULL, // #581
+NULL, // #582
+NULL, // #583
+NULL, // #584
+NULL, // #585
+NULL, // #586
+NULL, // #587
+NULL, // #588
+NULL, // #589
+NULL, // #590
+NULL, // #591
+NULL, // #592
+NULL, // #593
+NULL, // #594
+NULL, // #595
+NULL, // #596
+NULL, // #597
+NULL, // #598
+NULL, // #599
+NULL, // #600
+NULL, // #601
+NULL, // #602
+NULL, // #603
+NULL, // #604
+NULL, // #605
+NULL, // #606
+NULL, // #607
+NULL, // #608
+NULL, // #609
+NULL, // #610
+NULL, // #611
+NULL, // #612
+NULL, // #613
+NULL, // #614
+NULL, // #615
+NULL, // #616
+NULL, // #617
+NULL, // #618
+NULL, // #619
+NULL, // #620
+NULL, // #621
+NULL, // #622
+NULL, // #623
+VM_getextresponse, // #624 string getextresponse(void)
+NULL, // #625
};
const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);