3 #include "cl_collision.h"
6 //============================================================================
8 //[515]: unsolved PROBLEMS
9 //- finish player physics code (cs_runplayerphysics)
11 //- RF_DEPTHHACK is not like it should be
12 //- add builtin that sets cl.viewangles instead of reading "input_angles" global
13 //- finish lines support for R_Polygon***
14 //- insert selecttraceline into traceline somehow
16 //4 feature darkplaces csqc: add builtin to clientside qc for reading triangles of model meshes (useful to orient a ui along a triangle of a model mesh)
17 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
19 sfx_t *S_FindName(const char *name);
20 int Sbar_GetPlayer (int index);
21 void Sbar_SortFrags (void);
22 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
23 void CSQC_RelinkAllEntities (int drawmask);
24 void CSQC_RelinkCSQCEntities (void);
25 char *Key_GetBind (int key);
32 // #1 void(vector ang) makevectors
33 static void VM_CL_makevectors (void)
35 VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
36 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up);
39 // #2 void(entity e, vector o) setorigin
40 static void VM_CL_setorigin (void)
44 VM_SAFEPARMCOUNT(2, VM_CL_setorigin);
46 e = PRVM_G_EDICT(OFS_PARM0);
47 if (e == prog->edicts)
49 VM_Warning("setorigin: can not modify world entity\n");
52 if (e->priv.required->free)
54 VM_Warning("setorigin: can not modify free entity\n");
57 org = PRVM_G_VECTOR(OFS_PARM1);
58 VectorCopy (org, e->fields.client->origin);
62 // #3 void(entity e, string m) setmodel
63 static void VM_CL_setmodel (void)
70 VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
72 e = PRVM_G_EDICT(OFS_PARM0);
73 m = PRVM_G_STRING(OFS_PARM1);
74 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
76 if (!strcmp(cl.csqc_model_precache[i]->name, m))
78 e->fields.client->model = PRVM_SetEngineString(cl.csqc_model_precache[i]->name);
79 e->fields.client->modelindex = -(i+1);
84 for (i = 0;i < MAX_MODELS;i++)
86 mod = cl.model_precache[i];
87 if (mod && !strcmp(mod->name, m))
89 e->fields.client->model = PRVM_SetEngineString(mod->name);
90 e->fields.client->modelindex = i;
95 e->fields.client->modelindex = 0;
96 e->fields.client->model = 0;
99 // #4 void(entity e, vector min, vector max) setsize
100 static void VM_CL_setsize (void)
104 VM_SAFEPARMCOUNT(3, VM_CL_setsize);
106 e = PRVM_G_EDICT(OFS_PARM0);
107 if (e == prog->edicts)
109 VM_Warning("setsize: can not modify world entity\n");
112 if (e->priv.server->free)
114 VM_Warning("setsize: can not modify free entity\n");
117 min = PRVM_G_VECTOR(OFS_PARM1);
118 max = PRVM_G_VECTOR(OFS_PARM2);
120 VectorCopy (min, e->fields.client->mins);
121 VectorCopy (max, e->fields.client->maxs);
122 VectorSubtract (max, min, e->fields.client->size);
127 // #8 void(entity e, float chan, string samp, float volume, float atten) sound
128 static void VM_CL_sound (void)
132 prvm_edict_t *entity;
136 VM_SAFEPARMCOUNT(5, VM_CL_sound);
138 entity = PRVM_G_EDICT(OFS_PARM0);
139 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
140 sample = PRVM_G_STRING(OFS_PARM2);
141 volume = (int)(PRVM_G_FLOAT(OFS_PARM3)*255.0f);
142 attenuation = PRVM_G_FLOAT(OFS_PARM4);
144 if (volume < 0 || volume > 255)
146 VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
150 if (attenuation < 0 || attenuation > 4)
152 VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
156 if (channel < 0 || channel > 7)
158 VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
162 S_StartSound(32768 + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), entity->fields.client->origin, volume, attenuation);
165 // #14 entity() spawn
166 static void VM_CL_spawn (void)
169 ed = PRVM_ED_Alloc();
170 ed->fields.client->entnum = PRVM_NUM_FOR_EDICT(ed); //[515]: not needed any more ?
174 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
175 static void VM_CL_traceline (void)
182 VM_SAFEPARMCOUNTRANGE(4, 8, VM_CL_traceline); // allow more parameters for future expansion
184 prog->xfunction->builtinsprofile += 30;
186 v1 = PRVM_G_VECTOR(OFS_PARM0);
187 v2 = PRVM_G_VECTOR(OFS_PARM1);
188 move = (int)PRVM_G_FLOAT(OFS_PARM2);
189 ent = PRVM_G_EDICT(OFS_PARM3);
191 if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
192 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));
194 trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
196 VM_SetTraceGlobals(&trace);
203 Used for use tracing and shot targeting
204 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
205 if the tryents flag is set.
207 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
210 // LordHavoc: added this for my own use, VERY useful, similar to traceline
211 static void VM_CL_tracebox (void)
213 float *v1, *v2, *m1, *m2;
218 VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
220 prog->xfunction->builtinsprofile += 30;
222 v1 = PRVM_G_VECTOR(OFS_PARM0);
223 m1 = PRVM_G_VECTOR(OFS_PARM1);
224 m2 = PRVM_G_VECTOR(OFS_PARM2);
225 v2 = PRVM_G_VECTOR(OFS_PARM3);
226 move = (int)PRVM_G_FLOAT(OFS_PARM4);
227 ent = PRVM_G_EDICT(OFS_PARM5);
229 if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
230 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));
232 trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
234 VM_SetTraceGlobals(&trace);
237 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
242 vec3_t original_origin;
243 vec3_t original_velocity;
244 vec3_t original_angles;
245 vec3_t original_avelocity;
249 VectorCopy(tossent->fields.client->origin , original_origin );
250 VectorCopy(tossent->fields.client->velocity , original_velocity );
251 VectorCopy(tossent->fields.client->angles , original_angles );
252 VectorCopy(tossent->fields.client->avelocity, original_avelocity);
254 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
255 if (val != NULL && val->_float != 0)
256 gravity = val->_float;
259 gravity *= cl.movevars_gravity * 0.05;
261 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
263 tossent->fields.client->velocity[2] -= gravity;
264 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
265 VectorScale (tossent->fields.client->velocity, 0.05, move);
266 VectorAdd (tossent->fields.client->origin, move, end);
267 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);
268 VectorCopy (trace.endpos, tossent->fields.client->origin);
270 if (trace.fraction < 1)
274 VectorCopy(original_origin , tossent->fields.client->origin );
275 VectorCopy(original_velocity , tossent->fields.client->velocity );
276 VectorCopy(original_angles , tossent->fields.client->angles );
277 VectorCopy(original_avelocity, tossent->fields.client->avelocity);
282 static void VM_CL_tracetoss (void)
286 prvm_edict_t *ignore;
288 prog->xfunction->builtinsprofile += 600;
290 VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
292 ent = PRVM_G_EDICT(OFS_PARM0);
293 if (ent == prog->edicts)
295 VM_Warning("tracetoss: can not use world entity\n");
298 ignore = PRVM_G_EDICT(OFS_PARM1);
300 trace = CL_Trace_Toss (ent, ignore);
302 VM_SetTraceGlobals(&trace);
306 // #20 void(string s) precache_model
307 static void VM_CL_precache_model (void)
313 VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
315 name = PRVM_G_STRING(OFS_PARM0);
316 for (i = 1;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
318 if(!strcmp(cl.csqc_model_precache[i]->name, name))
320 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
324 PRVM_G_FLOAT(OFS_RETURN) = 0;
325 m = Mod_ForName(name, false, false, false);
328 for (i = 1;i < MAX_MODELS;i++)
330 if (!cl.csqc_model_precache[i])
332 cl.csqc_model_precache[i] = (model_t*)m;
333 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
337 VM_Warning("VM_CL_precache_model: no free models\n");
340 VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
343 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
348 ent = PRVM_NEXT_EDICT(prog->edicts);
349 for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
351 if (ent->priv.required->free)
353 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
359 // #22 entity(vector org, float rad) findradius
360 static void VM_CL_findradius (void)
362 prvm_edict_t *ent, *chain;
363 vec_t radius, radius2;
364 vec3_t org, eorg, mins, maxs;
365 int i, numtouchedicts;
366 prvm_edict_t *touchedicts[MAX_EDICTS];
368 VM_SAFEPARMCOUNT(2, VM_CL_findradius);
370 chain = (prvm_edict_t *)prog->edicts;
372 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
373 radius = PRVM_G_FLOAT(OFS_PARM1);
374 radius2 = radius * radius;
376 mins[0] = org[0] - (radius + 1);
377 mins[1] = org[1] - (radius + 1);
378 mins[2] = org[2] - (radius + 1);
379 maxs[0] = org[0] + (radius + 1);
380 maxs[1] = org[1] + (radius + 1);
381 maxs[2] = org[2] + (radius + 1);
382 numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
383 if (numtouchedicts > MAX_EDICTS)
385 // this never happens //[515]: for what then ?
386 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
387 numtouchedicts = MAX_EDICTS;
389 for (i = 0;i < numtouchedicts;i++)
391 ent = touchedicts[i];
392 // Quake did not return non-solid entities but darkplaces does
393 // (note: this is the reason you can't blow up fallen zombies)
394 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
396 // LordHavoc: compare against bounding box rather than center so it
397 // doesn't miss large objects, and use DotProduct instead of Length
398 // for a major speedup
399 VectorSubtract(org, ent->fields.client->origin, eorg);
400 if (sv_gameplayfix_findradiusdistancetobox.integer)
402 eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
403 eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
404 eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
407 VectorMAMAM(1, eorg, 0.5f, ent->fields.client->mins, 0.5f, ent->fields.client->maxs, eorg);
408 if (DotProduct(eorg, eorg) < radius2)
410 ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
415 VM_RETURN_EDICT(chain);
418 // #34 float() droptofloor
419 static void VM_CL_droptofloor (void)
426 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
428 // assume failure if it returns early
429 PRVM_G_FLOAT(OFS_RETURN) = 0;
431 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
432 if (ent == prog->edicts)
434 VM_Warning("droptofloor: can not modify world entity\n");
437 if (ent->priv.server->free)
439 VM_Warning("droptofloor: can not modify free entity\n");
443 VectorCopy (ent->fields.client->origin, end);
446 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);
448 if (trace.fraction != 1)
450 VectorCopy (trace.endpos, ent->fields.client->origin);
451 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
452 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
453 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
454 PRVM_G_FLOAT(OFS_RETURN) = 1;
455 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
456 // ent->priv.server->suspendedinairflag = true;
460 // #35 void(float style, string value) lightstyle
461 static void VM_CL_lightstyle (void)
466 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
468 i = (int)PRVM_G_FLOAT(OFS_PARM0);
469 c = PRVM_G_STRING(OFS_PARM1);
470 if (i >= cl.max_lightstyle)
472 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
475 strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
476 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
477 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
480 // #40 float(entity e) checkbottom
481 static void VM_CL_checkbottom (void)
483 static int cs_yes, cs_no;
485 vec3_t mins, maxs, start, stop;
490 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
491 ent = PRVM_G_EDICT(OFS_PARM0);
492 PRVM_G_FLOAT(OFS_RETURN) = 0;
494 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
495 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
497 // if all of the points under the corners are solid world, don't bother
498 // with the tougher checks
499 // the corners must be within 16 of the midpoint
500 start[2] = mins[2] - 1;
501 for (x=0 ; x<=1 ; x++)
502 for (y=0 ; y<=1 ; y++)
504 start[0] = x ? maxs[0] : mins[0];
505 start[1] = y ? maxs[1] : mins[1];
506 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
511 PRVM_G_FLOAT(OFS_RETURN) = true;
512 return; // we got out easy
517 // check it for real...
521 // the midpoint must be within 16 of the bottom
522 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
523 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
524 stop[2] = start[2] - 2*sv_stepheight.value;
525 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
527 if (trace.fraction == 1.0)
530 mid = bottom = trace.endpos[2];
532 // the corners must be within 16 of the midpoint
533 for (x=0 ; x<=1 ; x++)
534 for (y=0 ; y<=1 ; y++)
536 start[0] = stop[0] = x ? maxs[0] : mins[0];
537 start[1] = stop[1] = y ? maxs[1] : mins[1];
539 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
541 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
542 bottom = trace.endpos[2];
543 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
548 PRVM_G_FLOAT(OFS_RETURN) = true;
551 // #41 float(vector v) pointcontents
552 static void VM_CL_pointcontents (void)
554 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
555 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
558 // #48 void(vector o, vector d, float color, float count) particle
559 static void VM_CL_particle (void)
564 VM_SAFEPARMCOUNT(4, VM_CL_particle);
566 org = PRVM_G_VECTOR(OFS_PARM0);
567 dir = PRVM_G_VECTOR(OFS_PARM1);
568 color = (int)PRVM_G_FLOAT(OFS_PARM2);
569 count = (int)PRVM_G_FLOAT(OFS_PARM3);
570 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
573 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
574 static void VM_CL_ambientsound (void)
578 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
579 s = S_FindName(PRVM_G_STRING(OFS_PARM0));
580 f = PRVM_G_VECTOR(OFS_PARM1);
581 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
584 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
585 static void VM_CL_getlight (void)
587 vec3_t ambientcolor, diffusecolor, diffusenormal;
590 VM_SAFEPARMCOUNT(1, VM_CL_getlight);
592 p = PRVM_G_VECTOR(OFS_PARM0);
593 VectorClear(ambientcolor);
594 VectorClear(diffusecolor);
595 VectorClear(diffusenormal);
596 if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
597 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
598 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
602 //============================================================================
603 //[515]: SCENE MANAGER builtins
604 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
606 static void CSQC_R_RecalcView (void)
608 extern matrix4x4_t viewmodelmatrix;
609 Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], 1);
610 Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], cl_viewmodel_scale.value);
613 void CL_RelinkLightFlashes(void);
614 //#300 void() clearscene (EXT_CSQC)
615 static void VM_CL_R_ClearScene (void)
617 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
618 // clear renderable entity and light lists
619 r_refdef.numentities = 0;
620 r_refdef.numlights = 0;
621 // FIXME: restore these to the values from VM_CL_UpdateView
625 r_view.width = vid.width;
626 r_view.height = vid.height;
628 // FIXME: restore frustum_x/frustum_y
629 r_view.useperspective = true;
630 r_view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
631 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
632 r_view.frustum_x *= r_refdef.frustumscale_x;
633 r_view.frustum_y *= r_refdef.frustumscale_y;
634 // FIXME: restore cl.csqc_origin
635 // FIXME: restore cl.csqc_angles
636 cl.csqc_vidvars.drawworld = true;
637 cl.csqc_vidvars.drawenginesbar = false;
638 cl.csqc_vidvars.drawcrosshair = false;
641 //#301 void(float mask) addentities (EXT_CSQC)
642 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
643 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
644 static void VM_CL_R_AddEntities (void)
648 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
649 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
650 CSQC_RelinkAllEntities(drawmask);
651 CL_RelinkLightFlashes();
653 prog->globals.client->time = cl.time;
654 for(i=1;i<prog->num_edicts;i++)
656 ed = &prog->edicts[i];
657 if(ed->priv.required->free)
660 if(ed->priv.required->free)
662 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
664 if(ed->priv.required->free)
666 if(!((int)ed->fields.client->drawmask & drawmask))
668 CSQC_AddRenderEdict(ed);
672 //#302 void(entity ent) addentity (EXT_CSQC)
673 static void VM_CL_R_AddEntity (void)
675 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
676 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
679 //#303 float(float property, ...) setproperty (EXT_CSQC)
680 static void VM_CL_R_SetView (void)
686 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
688 c = (int)PRVM_G_FLOAT(OFS_PARM0);
689 f = PRVM_G_VECTOR(OFS_PARM1);
690 k = PRVM_G_FLOAT(OFS_PARM1);
694 case VF_MIN: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
695 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
697 case VF_MIN_X: r_view.x = (int)(k * vid.width / vid_conwidth.value);
699 case VF_MIN_Y: r_view.y = (int)(k * vid.height / vid_conheight.value);
701 case VF_SIZE: r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
702 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
704 case VF_SIZE_Y: r_view.width = (int)(k * vid.width / vid_conwidth.value);
706 case VF_SIZE_X: r_view.height = (int)(k * vid.height / vid_conheight.value);
708 case VF_VIEWPORT: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
709 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
710 f = PRVM_G_VECTOR(OFS_PARM2);
711 r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
712 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
714 case VF_FOV: r_view.frustum_x = tan(f[0] * M_PI / 360.0);
715 r_view.frustum_y = tan(f[1] * M_PI / 360.0);
717 case VF_FOVX: r_view.frustum_x = tan(k * M_PI / 360.0);
719 case VF_FOVY: r_view.frustum_y = tan(k * M_PI / 360.0);
721 case VF_ORIGIN: VectorCopy(f, cl.csqc_origin);
724 case VF_ORIGIN_X: cl.csqc_origin[0] = k;
727 case VF_ORIGIN_Y: cl.csqc_origin[1] = k;
730 case VF_ORIGIN_Z: cl.csqc_origin[2] = k;
733 case VF_ANGLES: VectorCopy(f, cl.csqc_angles);
736 case VF_ANGLES_X: cl.csqc_angles[0] = k;
739 case VF_ANGLES_Y: cl.csqc_angles[1] = k;
742 case VF_ANGLES_Z: cl.csqc_angles[2] = k;
745 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
747 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
749 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
752 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
754 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
756 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
758 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
761 case VF_PERSPECTIVE: r_view.useperspective = k != 0;
764 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
765 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
768 PRVM_G_FLOAT(OFS_RETURN) = 1;
771 //#304 void() renderscene (EXT_CSQC)
772 static void VM_CL_R_RenderScene (void)
774 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
775 // we need to update any RENDER_VIEWMODEL entities at this point because
776 // csqc supplies its own view matrix
777 CL_UpdateViewEntities();
782 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
783 static void VM_CL_R_AddDynamicLight (void)
787 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
789 // if we've run out of dlights, just return
790 if (r_refdef.numlights >= MAX_DLIGHTS)
793 pos = PRVM_G_VECTOR(OFS_PARM0);
794 col = PRVM_G_VECTOR(OFS_PARM2);
795 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
796 R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &matrix, col, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
799 //============================================================================
801 //#310 vector (vector v) cs_unproject (EXT_CSQC)
802 static void VM_CL_unproject (void)
807 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
808 f = PRVM_G_VECTOR(OFS_PARM0);
809 VectorSet(temp, f[2], f[0] * f[2] * -r_view.frustum_x * 2.0 / r_view.width, f[1] * f[2] * -r_view.frustum_y * 2.0 / r_view.height);
810 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
813 //#311 vector (vector v) cs_project (EXT_CSQC)
814 static void VM_CL_project (void)
820 VM_SAFEPARMCOUNT(1, VM_CL_project);
821 f = PRVM_G_VECTOR(OFS_PARM0);
822 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
823 Matrix4x4_Transform(&m, f, v);
824 VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_view.frustum_x*0.5*r_view.width, v[2]/v[0]/-r_view.frustum_y*r_view.height*0.5, v[0]);
827 //#330 float(float stnum) getstatf (EXT_CSQC)
828 static void VM_CL_getstatf (void)
836 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
837 i = (int)PRVM_G_FLOAT(OFS_PARM0);
838 if(i < 0 || i >= MAX_CL_STATS)
840 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
844 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
847 //#331 float(float stnum) getstati (EXT_CSQC)
848 static void VM_CL_getstati (void)
851 VM_SAFEPARMCOUNT(1, VM_CL_getstati);
852 index = (int)PRVM_G_FLOAT(OFS_PARM0);
854 if(index < 0 || index >= MAX_CL_STATS)
856 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
860 PRVM_G_FLOAT(OFS_RETURN) = i;
863 //#332 string(float firststnum) getstats (EXT_CSQC)
864 static void VM_CL_getstats (void)
868 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
869 i = (int)PRVM_G_FLOAT(OFS_PARM0);
870 if(i < 0 || i > MAX_CL_STATS-4)
872 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
873 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
876 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
877 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
880 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
881 static void VM_CL_setmodelindex (void)
885 struct model_s *model;
887 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
889 t = PRVM_G_EDICT(OFS_PARM0);
891 i = (int)PRVM_G_FLOAT(OFS_PARM1);
893 t->fields.client->model = 0;
894 t->fields.client->modelindex = 0;
899 model = CL_GetModelByIndex(i);
902 VM_Warning("VM_CL_setmodelindex: null model\n");
905 t->fields.client->model = PRVM_SetEngineString(model->name);
906 t->fields.client->modelindex = i;
909 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
910 static void VM_CL_modelnameforindex (void)
914 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
916 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
917 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
918 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
921 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
922 static void VM_CL_particleeffectnum (void)
925 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
926 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
929 PRVM_G_FLOAT(OFS_RETURN) = i;
932 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
933 static void VM_CL_trailparticles (void)
938 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
940 t = PRVM_G_EDICT(OFS_PARM0);
941 i = (int)PRVM_G_FLOAT(OFS_PARM1);
942 start = PRVM_G_VECTOR(OFS_PARM2);
943 end = PRVM_G_VECTOR(OFS_PARM3);
945 CL_ParticleEffect(i, VectorDistance(start, end), start, end, t->fields.client->velocity, t->fields.client->velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
948 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
949 static void VM_CL_pointparticles (void)
953 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
954 i = (int)PRVM_G_FLOAT(OFS_PARM0);
955 f = PRVM_G_VECTOR(OFS_PARM1);
956 v = PRVM_G_VECTOR(OFS_PARM2);
957 n = (int)PRVM_G_FLOAT(OFS_PARM3);
958 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
961 //#342 string(float keynum) getkeybind (EXT_CSQC)
962 static void VM_CL_getkeybind (void)
964 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
965 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
968 //#343 void(float usecursor) setcursormode (EXT_CSQC)
969 static void VM_CL_setcursormode (void)
971 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
972 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
973 cl_ignoremousemove = true;
976 //#345 float(float framenum) getinputstate (EXT_CSQC)
977 static void VM_CL_getinputstate (void)
980 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
981 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
982 for (i = 0;i < cl.movement_numqueue;i++)
983 if (cl.movement_queue[i].sequence == frame)
985 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
986 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
987 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
988 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
989 if(cl.movement_queue[i].crouch)
991 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
992 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
996 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
997 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1002 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1003 static void VM_CL_setsensitivityscale (void)
1005 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1006 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1009 //#347 void() runstandardplayerphysics (EXT_CSQC)
1010 static void VM_CL_runplayerphysics (void)
1014 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1015 static void VM_CL_getplayerkey (void)
1021 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1023 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1024 c = PRVM_G_STRING(OFS_PARM1);
1025 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1028 i = Sbar_GetPlayer(i);
1034 if(!strcasecmp(c, "name"))
1035 strlcpy(t, cl.scores[i].name, sizeof(t));
1037 if(!strcasecmp(c, "frags"))
1038 sprintf(t, "%i", cl.scores[i].frags);
1040 if(!strcasecmp(c, "ping"))
1041 sprintf(t, "%i", cl.scores[i].qw_ping);
1043 if(!strcasecmp(c, "entertime"))
1044 sprintf(t, "%f", cl.scores[i].qw_entertime);
1046 if(!strcasecmp(c, "colors"))
1047 sprintf(t, "%i", cl.scores[i].colors);
1049 if(!strcasecmp(c, "topcolor"))
1050 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1052 if(!strcasecmp(c, "bottomcolor"))
1053 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1055 if(!strcasecmp(c, "viewentity"))
1056 sprintf(t, "%i", i+1);
1059 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1062 //#349 float() isdemo (EXT_CSQC)
1063 static void VM_CL_isdemo (void)
1065 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1066 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1069 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1070 static void VM_CL_setlistener (void)
1072 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1073 Matrix4x4_FromVectors(&cl.csqc_listenermatrix, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_VECTOR(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0));
1074 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1077 //#352 void(string cmdname) registercommand (EXT_CSQC)
1078 static void VM_CL_registercmd (void)
1081 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1082 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1086 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1087 t = (char *)Z_Malloc(alloclen);
1088 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1089 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1092 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1096 //#360 float() readbyte (EXT_CSQC)
1097 static void VM_CL_ReadByte (void)
1099 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1100 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1103 //#361 float() readchar (EXT_CSQC)
1104 static void VM_CL_ReadChar (void)
1106 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1107 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1110 //#362 float() readshort (EXT_CSQC)
1111 static void VM_CL_ReadShort (void)
1113 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1114 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1117 //#363 float() readlong (EXT_CSQC)
1118 static void VM_CL_ReadLong (void)
1120 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1121 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1124 //#364 float() readcoord (EXT_CSQC)
1125 static void VM_CL_ReadCoord (void)
1127 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1128 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1131 //#365 float() readangle (EXT_CSQC)
1132 static void VM_CL_ReadAngle (void)
1134 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1135 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1138 //#366 string() readstring (EXT_CSQC)
1139 static void VM_CL_ReadString (void)
1141 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1142 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1145 //#367 float() readfloat (EXT_CSQC)
1146 static void VM_CL_ReadFloat (void)
1148 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1149 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1152 //////////////////////////////////////////////////////////
1154 static void VM_CL_makestatic (void)
1158 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1160 ent = PRVM_G_EDICT(OFS_PARM0);
1161 if (ent == prog->edicts)
1163 VM_Warning("makestatic: can not modify world entity\n");
1166 if (ent->priv.server->free)
1168 VM_Warning("makestatic: can not modify free entity\n");
1172 if (cl.num_static_entities < cl.max_static_entities)
1176 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1178 // copy it to the current state
1179 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1180 staticent->render.frame = staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1181 staticent->render.framelerp = 0;
1182 // make torchs play out of sync
1183 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1184 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1185 staticent->render.skinnum = (int)ent->fields.client->skin;
1186 staticent->render.effects = (int)ent->fields.client->effects;
1187 staticent->render.alpha = 1;
1188 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1189 staticent->render.scale = 1;
1190 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1191 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1194 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1195 if (renderflags & RF_USEAXIS)
1198 VectorNegate(prog->globals.client->v_right, left);
1199 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1200 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1203 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);
1204 CL_UpdateRenderEntity(&staticent->render);
1206 // either fullbright or lit
1207 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1208 staticent->render.flags |= RENDER_LIGHT;
1209 // turn off shadows from transparent objects
1210 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1211 staticent->render.flags |= RENDER_SHADOW;
1214 Con_Printf("Too many static entities");
1216 // throw the entity away now
1220 //=================================================================//
1226 copies data from one entity to another
1228 copyentity(src, dst)
1231 static void VM_CL_copyentity (void)
1233 prvm_edict_t *in, *out;
1234 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1235 in = PRVM_G_EDICT(OFS_PARM0);
1236 if (in == prog->edicts)
1238 VM_Warning("copyentity: can not read world entity\n");
1241 if (in->priv.server->free)
1243 VM_Warning("copyentity: can not read free entity\n");
1246 out = PRVM_G_EDICT(OFS_PARM1);
1247 if (out == prog->edicts)
1249 VM_Warning("copyentity: can not modify world entity\n");
1252 if (out->priv.server->free)
1254 VM_Warning("copyentity: can not modify free entity\n");
1257 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1261 //=================================================================//
1263 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1264 static void VM_CL_effect (void)
1266 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1267 CL_Effect(PRVM_G_VECTOR(OFS_PARM0), (int)PRVM_G_FLOAT(OFS_PARM1), (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
1270 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1271 static void VM_CL_te_blood (void)
1275 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1276 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1278 pos = PRVM_G_VECTOR(OFS_PARM0);
1279 CL_FindNonSolidLocation(pos, pos2, 4);
1280 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1283 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1284 static void VM_CL_te_bloodshower (void)
1288 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1289 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1291 speed = PRVM_G_FLOAT(OFS_PARM2);
1298 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1301 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1302 static void VM_CL_te_explosionrgb (void)
1306 matrix4x4_t tempmatrix;
1307 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1308 pos = PRVM_G_VECTOR(OFS_PARM0);
1309 CL_FindNonSolidLocation(pos, pos2, 10);
1310 CL_ParticleExplosion(pos2);
1311 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1312 CL_AllocLightFlash(NULL, &tempmatrix, 350, PRVM_G_VECTOR(OFS_PARM1)[0], PRVM_G_VECTOR(OFS_PARM1)[1], PRVM_G_VECTOR(OFS_PARM1)[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1315 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1316 static void VM_CL_te_particlecube (void)
1318 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1319 CL_ParticleCube(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), PRVM_G_FLOAT(OFS_PARM5), PRVM_G_FLOAT(OFS_PARM6));
1322 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1323 static void VM_CL_te_particlerain (void)
1325 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1326 CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 0);
1329 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1330 static void VM_CL_te_particlesnow (void)
1332 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1333 CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 1);
1336 // #411 void(vector org, vector vel, float howmany) te_spark
1337 static void VM_CL_te_spark (void)
1341 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1343 pos = PRVM_G_VECTOR(OFS_PARM0);
1344 CL_FindNonSolidLocation(pos, pos2, 4);
1345 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1348 extern cvar_t cl_sound_ric_gunshot;
1349 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1350 static void VM_CL_te_gunshotquad (void)
1355 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1357 pos = PRVM_G_VECTOR(OFS_PARM0);
1358 CL_FindNonSolidLocation(pos, pos2, 4);
1359 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1360 if(cl_sound_ric_gunshot.integer >= 2)
1362 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1366 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1367 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1368 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1373 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1374 static void VM_CL_te_spikequad (void)
1379 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1381 pos = PRVM_G_VECTOR(OFS_PARM0);
1382 CL_FindNonSolidLocation(pos, pos2, 4);
1383 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1384 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1388 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1389 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1390 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1394 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1395 static void VM_CL_te_superspikequad (void)
1400 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1402 pos = PRVM_G_VECTOR(OFS_PARM0);
1403 CL_FindNonSolidLocation(pos, pos2, 4);
1404 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1405 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1409 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1410 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1411 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1415 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1416 static void VM_CL_te_explosionquad (void)
1420 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1422 pos = PRVM_G_VECTOR(OFS_PARM0);
1423 CL_FindNonSolidLocation(pos, pos2, 10);
1424 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1425 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1428 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1429 static void VM_CL_te_smallflash (void)
1433 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1435 pos = PRVM_G_VECTOR(OFS_PARM0);
1436 CL_FindNonSolidLocation(pos, pos2, 10);
1437 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1440 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1441 static void VM_CL_te_customflash (void)
1445 matrix4x4_t tempmatrix;
1446 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1448 pos = PRVM_G_VECTOR(OFS_PARM0);
1449 CL_FindNonSolidLocation(pos, pos2, 4);
1450 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1451 CL_AllocLightFlash(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM3)[0], PRVM_G_VECTOR(OFS_PARM3)[1], PRVM_G_VECTOR(OFS_PARM3)[2], PRVM_G_FLOAT(OFS_PARM1) / PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM2), 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1454 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1455 static void VM_CL_te_gunshot (void)
1460 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1462 pos = PRVM_G_VECTOR(OFS_PARM0);
1463 CL_FindNonSolidLocation(pos, pos2, 4);
1464 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1465 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1467 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1471 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1472 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1473 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1478 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1479 static void VM_CL_te_spike (void)
1484 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1486 pos = PRVM_G_VECTOR(OFS_PARM0);
1487 CL_FindNonSolidLocation(pos, pos2, 4);
1488 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1489 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1493 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1494 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1495 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1499 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1500 static void VM_CL_te_superspike (void)
1505 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1507 pos = PRVM_G_VECTOR(OFS_PARM0);
1508 CL_FindNonSolidLocation(pos, pos2, 4);
1509 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1510 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1514 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1515 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1516 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1520 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1521 static void VM_CL_te_explosion (void)
1525 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1527 pos = PRVM_G_VECTOR(OFS_PARM0);
1528 CL_FindNonSolidLocation(pos, pos2, 10);
1529 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1530 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1533 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1534 static void VM_CL_te_tarexplosion (void)
1538 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1540 pos = PRVM_G_VECTOR(OFS_PARM0);
1541 CL_FindNonSolidLocation(pos, pos2, 10);
1542 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1543 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1546 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1547 static void VM_CL_te_wizspike (void)
1551 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1553 pos = PRVM_G_VECTOR(OFS_PARM0);
1554 CL_FindNonSolidLocation(pos, pos2, 4);
1555 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1556 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1559 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1560 static void VM_CL_te_knightspike (void)
1564 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1566 pos = PRVM_G_VECTOR(OFS_PARM0);
1567 CL_FindNonSolidLocation(pos, pos2, 4);
1568 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1569 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1572 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1573 static void VM_CL_te_lavasplash (void)
1575 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1576 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1579 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1580 static void VM_CL_te_teleport (void)
1582 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1583 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1586 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1587 static void VM_CL_te_explosion2 (void)
1591 matrix4x4_t tempmatrix;
1592 int colorStart, colorLength;
1593 unsigned char *tempcolor;
1594 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1596 pos = PRVM_G_VECTOR(OFS_PARM0);
1597 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1598 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1599 CL_FindNonSolidLocation(pos, pos2, 10);
1600 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1601 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1602 color[0] = tempcolor[0] * (2.0f / 255.0f);
1603 color[1] = tempcolor[1] * (2.0f / 255.0f);
1604 color[2] = tempcolor[2] * (2.0f / 255.0f);
1605 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1606 CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1607 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1611 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1612 static void VM_CL_te_lightning1 (void)
1614 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1615 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1618 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1619 static void VM_CL_te_lightning2 (void)
1621 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1622 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1625 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1626 static void VM_CL_te_lightning3 (void)
1628 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1629 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1632 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1633 static void VM_CL_te_beam (void)
1635 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1636 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1639 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1640 static void VM_CL_te_plasmaburn (void)
1644 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1646 pos = PRVM_G_VECTOR(OFS_PARM0);
1647 CL_FindNonSolidLocation(pos, pos2, 4);
1648 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1651 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1652 static void VM_CL_te_flamejet (void)
1656 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1657 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1659 pos = PRVM_G_VECTOR(OFS_PARM0);
1660 CL_FindNonSolidLocation(pos, pos2, 4);
1661 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1665 //====================================================================
1668 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1670 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1672 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1674 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1677 // #434 float(entity e, float s) getsurfacenumpoints
1678 static void VM_CL_getsurfacenumpoints(void)
1681 msurface_t *surface;
1682 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1683 // return 0 if no such surface
1684 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1686 PRVM_G_FLOAT(OFS_RETURN) = 0;
1690 // note: this (incorrectly) assumes it is a simple polygon
1691 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1694 // #435 vector(entity e, float s, float n) getsurfacepoint
1695 static void VM_CL_getsurfacepoint(void)
1699 msurface_t *surface;
1701 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1702 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1703 ed = PRVM_G_EDICT(OFS_PARM0);
1704 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1706 // note: this (incorrectly) assumes it is a simple polygon
1707 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1708 if (pointnum < 0 || pointnum >= surface->num_vertices)
1710 // FIXME: implement rotation/scaling
1711 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1714 // #436 vector(entity e, float s) getsurfacenormal
1715 static void VM_CL_getsurfacenormal(void)
1718 msurface_t *surface;
1720 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1721 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1722 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1724 // FIXME: implement rotation/scaling
1725 // note: this (incorrectly) assumes it is a simple polygon
1726 // note: this only returns the first triangle, so it doesn't work very
1727 // well for curved surfaces or arbitrary meshes
1728 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);
1729 VectorNormalize(normal);
1730 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1733 // #437 string(entity e, float s) getsurfacetexture
1734 static void VM_CL_getsurfacetexture(void)
1737 msurface_t *surface;
1738 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1739 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1740 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1742 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1745 // #438 float(entity e, vector p) getsurfacenearpoint
1746 static void VM_CL_getsurfacenearpoint(void)
1748 int surfacenum, best;
1750 vec_t dist, bestdist;
1752 model_t *model = NULL;
1753 msurface_t *surface;
1755 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1756 PRVM_G_FLOAT(OFS_RETURN) = -1;
1757 ed = PRVM_G_EDICT(OFS_PARM0);
1758 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1761 // FIXME: implement rotation/scaling
1762 point = PRVM_G_VECTOR(OFS_PARM1);
1763 VectorSubtract(point, ed->fields.client->origin, p);
1765 bestdist = 1000000000;
1766 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1768 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1769 // first see if the nearest point on the surface's box is closer than the previous match
1770 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1771 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1772 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1773 dist = VectorLength2(clipped);
1774 if (dist < bestdist)
1776 // it is, check the nearest point on the actual geometry
1777 clippointtosurface(model, surface, p, clipped);
1778 VectorSubtract(clipped, p, clipped);
1779 dist += VectorLength2(clipped);
1780 if (dist < bestdist)
1782 // that's closer too, store it as the best match
1788 PRVM_G_FLOAT(OFS_RETURN) = best;
1791 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1792 static void VM_CL_getsurfaceclippedpoint(void)
1796 msurface_t *surface;
1798 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1799 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1800 ed = PRVM_G_EDICT(OFS_PARM0);
1801 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1803 // FIXME: implement rotation/scaling
1804 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1805 clippointtosurface(model, surface, p, out);
1806 // FIXME: implement rotation/scaling
1807 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1810 // #443 void(entity e, entity tagentity, string tagname) setattachment
1811 static void VM_CL_setattachment (void)
1814 prvm_edict_t *tagentity;
1815 const char *tagname;
1819 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1821 e = PRVM_G_EDICT(OFS_PARM0);
1822 tagentity = PRVM_G_EDICT(OFS_PARM1);
1823 tagname = PRVM_G_STRING(OFS_PARM2);
1825 if (e == prog->edicts)
1827 VM_Warning("setattachment: can not modify world entity\n");
1830 if (e->priv.server->free)
1832 VM_Warning("setattachment: can not modify free entity\n");
1836 if (tagentity == NULL)
1837 tagentity = prog->edicts;
1839 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1841 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1843 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1846 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1848 modelindex = (int)tagentity->fields.client->modelindex;
1849 model = CL_GetModelByIndex(modelindex);
1852 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1854 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name);
1857 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity));
1861 /////////////////////////////////////////
1862 // DP_MD3_TAGINFO extension coded by VorteX
1864 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1866 model_t *model = CL_GetModelFromEdict(e);
1868 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1873 // Warnings/errors code:
1874 // 0 - normal (everything all-right)
1877 // 3 - null or non-precached model
1878 // 4 - no tags with requested index
1879 // 5 - runaway loop at attachment chain
1880 extern cvar_t cl_bob;
1881 extern cvar_t cl_bobcycle;
1882 extern cvar_t cl_bobup;
1883 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1886 int reqframe, attachloop;
1887 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1888 prvm_edict_t *attachent;
1891 *out = identitymatrix; // warnings and errors return identical matrix
1893 if (ent == prog->edicts)
1895 if (ent->priv.server->free)
1898 model = CL_GetModelFromEdict(ent);
1903 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1904 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1906 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1908 // get initial tag matrix
1911 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1916 tagmatrix = identitymatrix;
1918 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1919 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1923 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1924 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1926 model = CL_GetModelFromEdict(attachent);
1928 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1929 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1931 attachmatrix = identitymatrix;
1933 // apply transformation by child entity matrix
1934 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1935 if (val->_float == 0)
1937 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, 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], val->_float);
1938 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1939 Matrix4x4_Copy(&tagmatrix, out);
1941 // finally transformate by matrix of tag on parent entity
1942 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1943 Matrix4x4_Copy(&tagmatrix, out);
1947 if (attachloop > 255) // prevent runaway looping
1950 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1953 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1954 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1955 if (val->_float == 0)
1957 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1958 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, 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], val->_float);
1959 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1961 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1962 {// RENDER_VIEWMODEL magic
1963 Matrix4x4_Copy(&tagmatrix, out);
1965 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1966 if (val->_float == 0)
1969 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], val->_float);
1970 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1973 // Cl_bob, ported from rendering code
1974 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
1977 // LordHavoc: this code is *weird*, but not replacable (I think it
1978 // should be done in QC on the server, but oh well, quake is quake)
1979 // LordHavoc: figured out bobup: the time at which the sin is at 180
1980 // degrees (which allows lengthening or squishing the peak or valley)
1981 cycle = cl.time/cl_bobcycle.value;
1982 cycle -= (int)cycle;
1983 if (cycle < cl_bobup.value)
1984 cycle = sin(M_PI * cycle / cl_bobup.value);
1986 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
1987 // bob is proportional to velocity in the xy plane
1988 // (don't count Z, or jumping messes it up)
1989 bob = sqrt(ent->fields.client->velocity[0]*ent->fields.client->velocity[0] + ent->fields.client->velocity[1]*ent->fields.client->velocity[1])*cl_bob.value;
1990 bob = bob*0.3 + bob*0.7*cycle;
1991 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
1998 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
1999 static void VM_CL_gettagindex (void)
2002 const char *tag_name;
2003 int modelindex, tag_index;
2005 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2007 ent = PRVM_G_EDICT(OFS_PARM0);
2008 tag_name = PRVM_G_STRING(OFS_PARM1);
2009 if (ent == prog->edicts)
2011 VM_Warning("gettagindex: can't affect world entity\n");
2014 if (ent->priv.server->free)
2016 VM_Warning("gettagindex: can't affect free entity\n");
2020 modelindex = (int)ent->fields.client->modelindex;
2022 modelindex = -(modelindex+1);
2024 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2025 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2028 tag_index = CL_GetTagIndex(ent, tag_name);
2030 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2032 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2035 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2036 static void VM_CL_gettaginfo (void)
2040 matrix4x4_t tag_matrix;
2043 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2045 e = PRVM_G_EDICT(OFS_PARM0);
2046 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2047 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2048 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2053 VM_Warning("gettagindex: can't affect world entity\n");
2056 VM_Warning("gettagindex: can't affect free entity\n");
2059 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2062 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2065 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2070 //============================================================================
2072 //====================
2073 //QC POLYGON functions
2074 //====================
2079 float data[36]; //[515]: enough for polygons
2080 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2083 //static float vm_polygon_linewidth = 1;
2084 static mempool_t *vm_polygons_pool = NULL;
2085 static unsigned char vm_current_vertices = 0;
2086 static qboolean vm_polygons_initialized = false;
2087 static vm_polygon_t *vm_polygons = NULL;
2088 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2089 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2090 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2092 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2093 #define VM_POLYGON_FLLINES 32
2094 #define VM_POLYGON_FL2D 64
2095 #define VM_POLYGON_FL4V 128 //4 vertices
2097 static void VM_InitPolygons (void)
2099 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2100 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2101 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2102 vm_polygons_num = VM_DEFPOLYNUM;
2103 vm_drawpolygons_num = 0;
2104 vm_polygonbegin = false;
2105 vm_polygons_initialized = true;
2108 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2110 int surfacelistindex;
2111 // LordHavoc: FIXME: this is stupid code
2112 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2114 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2115 int flags = p->flags & 0x0f;
2117 if(flags == DRAWFLAG_ADDITIVE)
2118 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2119 else if(flags == DRAWFLAG_MODULATE)
2120 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2121 else if(flags == DRAWFLAG_2XMODULATE)
2122 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2124 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2126 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2129 //[515]: is speed is max ?
2130 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2132 qglLineWidth(p->data[13]);CHECKGLERROR
2133 qglBegin(GL_LINE_LOOP);
2134 qglTexCoord1f (p->data[12]);
2135 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2136 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2138 qglTexCoord1f (p->data[14]);
2139 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2140 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2142 if(p->flags & VM_POLYGON_FL3V)
2144 qglTexCoord1f (p->data[16]);
2145 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2146 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2148 if(p->flags & VM_POLYGON_FL4V)
2150 qglTexCoord1f (p->data[18]);
2151 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2152 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2160 qglBegin(GL_POLYGON);
2161 qglTexCoord2f (p->data[12], p->data[13]);
2162 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2163 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2165 qglTexCoord2f (p->data[14], p->data[15]);
2166 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2167 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2169 qglTexCoord2f (p->data[16], p->data[17]);
2170 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2171 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2173 if(p->flags & VM_POLYGON_FL4V)
2175 qglTexCoord2f (p->data[18], p->data[19]);
2176 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2177 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2185 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2187 drawqueuemesh_t mesh;
2188 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2190 mesh.texture = p->tex;
2191 mesh.data_element3i = picelements;
2192 mesh.data_vertex3f = p->data;
2193 mesh.data_texcoord2f = p->data + 12;
2194 mesh.data_color4f = p->data + 20;
2195 if(p->flags & VM_POLYGON_FL4V)
2197 mesh.num_vertices = 4;
2198 mesh.num_triangles = 2;
2202 mesh.num_vertices = 3;
2203 mesh.num_triangles = 1;
2205 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2206 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2208 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2211 void VM_CL_AddPolygonsToMeshQueue (void)
2214 if(!vm_drawpolygons_num)
2216 R_Mesh_Matrix(&identitymatrix);
2217 GL_CullFace(GL_NONE);
2218 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2219 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2220 vm_drawpolygons_num = 0;
2223 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2224 static void VM_CL_R_PolygonBegin (void)
2227 const char *picname;
2228 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2230 if(!vm_polygons_initialized)
2234 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2237 if(vm_drawpolygons_num >= vm_polygons_num)
2239 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2240 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2241 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2242 Mem_Free(vm_polygons);
2244 vm_polygons_num *= 2;
2246 p = &vm_polygons[vm_drawpolygons_num];
2247 picname = PRVM_G_STRING(OFS_PARM0);
2249 p->tex = Draw_CachePic(picname, true)->tex;
2251 p->tex = r_texture_white;
2252 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2253 vm_current_vertices = 0;
2254 vm_polygonbegin = true;
2257 if(PRVM_G_FLOAT(OFS_PARM2))
2258 p->flags |= VM_POLYGON_FL2D;
2259 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2261 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2262 p->flags |= VM_POLYGON_FLLINES;
2267 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2268 static void VM_CL_R_PolygonVertex (void)
2270 float *coords, *tx, *rgb, alpha;
2272 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2274 if(!vm_polygonbegin)
2276 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2279 coords = PRVM_G_VECTOR(OFS_PARM0);
2280 tx = PRVM_G_VECTOR(OFS_PARM1);
2281 rgb = PRVM_G_VECTOR(OFS_PARM2);
2282 alpha = PRVM_G_FLOAT(OFS_PARM3);
2284 p = &vm_polygons[vm_drawpolygons_num];
2285 if(vm_current_vertices > 4)
2287 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2291 p->data[vm_current_vertices*3] = coords[0];
2292 p->data[1+vm_current_vertices*3] = coords[1];
2293 p->data[2+vm_current_vertices*3] = coords[2];
2295 p->data[12+vm_current_vertices*2] = tx[0];
2296 if(!(p->flags & VM_POLYGON_FLLINES))
2297 p->data[13+vm_current_vertices*2] = tx[1];
2299 p->data[20+vm_current_vertices*4] = rgb[0];
2300 p->data[21+vm_current_vertices*4] = rgb[1];
2301 p->data[22+vm_current_vertices*4] = rgb[2];
2302 p->data[23+vm_current_vertices*4] = alpha;
2304 vm_current_vertices++;
2305 if(vm_current_vertices == 4)
2306 p->flags |= VM_POLYGON_FL4V;
2308 if(vm_current_vertices == 3)
2309 p->flags |= VM_POLYGON_FL3V;
2312 //void() R_EndPolygon
2313 static void VM_CL_R_PolygonEnd (void)
2315 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2316 if(!vm_polygonbegin)
2318 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2321 vm_polygonbegin = false;
2322 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2324 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2325 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2327 vm_drawpolygons_num++;
2330 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2333 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2337 if(!vm_polygons_initialized)
2341 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2344 // limit polygons to a vaguely sane amount, beyond this each one just
2345 // replaces the last one
2346 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2347 if(vm_drawpolygons_num >= vm_polygons_num)
2349 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2350 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2351 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2352 Mem_Free(vm_polygons);
2354 vm_polygons_num *= 2;
2356 p = &vm_polygons[vm_drawpolygons_num];
2357 if(picname && picname[0])
2358 p->tex = Draw_CachePic(picname, true)->tex;
2360 p->tex = r_texture_white;
2362 vm_current_vertices = 0;
2363 vm_polygonbegin = true;
2365 p->flags |= VM_POLYGON_FL2D;
2368 p->data[13] = linewidth; //[515]: linewidth
2369 p->flags |= VM_POLYGON_FLLINES;
2373 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2377 if(!vm_polygonbegin)
2379 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2383 p = &vm_polygons[vm_drawpolygons_num];
2384 if(vm_current_vertices > 4)
2386 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2390 p->data[vm_current_vertices*3] = x;
2391 p->data[1+vm_current_vertices*3] = y;
2392 p->data[2+vm_current_vertices*3] = z;
2394 p->data[12+vm_current_vertices*2] = s;
2395 if(!(p->flags & VM_POLYGON_FLLINES))
2396 p->data[13+vm_current_vertices*2] = t;
2398 p->data[20+vm_current_vertices*4] = r;
2399 p->data[21+vm_current_vertices*4] = g;
2400 p->data[22+vm_current_vertices*4] = b;
2401 p->data[23+vm_current_vertices*4] = a;
2403 vm_current_vertices++;
2404 if(vm_current_vertices == 4)
2405 p->flags |= VM_POLYGON_FL4V;
2407 if(vm_current_vertices == 3)
2408 p->flags |= VM_POLYGON_FL3V;
2411 void Debug_PolygonEnd(void)
2413 if(!vm_polygonbegin)
2415 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2418 vm_polygonbegin = false;
2419 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2421 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2422 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2424 vm_drawpolygons_num++;
2427 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2434 Returns false if any part of the bottom of the entity is off an edge that
2439 qboolean CL_CheckBottom (prvm_edict_t *ent)
2441 vec3_t mins, maxs, start, stop;
2446 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2447 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2449 // if all of the points under the corners are solid world, don't bother
2450 // with the tougher checks
2451 // the corners must be within 16 of the midpoint
2452 start[2] = mins[2] - 1;
2453 for (x=0 ; x<=1 ; x++)
2454 for (y=0 ; y<=1 ; y++)
2456 start[0] = x ? maxs[0] : mins[0];
2457 start[1] = y ? maxs[1] : mins[1];
2458 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2462 return true; // we got out easy
2466 // check it for real...
2470 // the midpoint must be within 16 of the bottom
2471 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2472 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2473 stop[2] = start[2] - 2*sv_stepheight.value;
2474 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2476 if (trace.fraction == 1.0)
2478 mid = bottom = trace.endpos[2];
2480 // the corners must be within 16 of the midpoint
2481 for (x=0 ; x<=1 ; x++)
2482 for (y=0 ; y<=1 ; y++)
2484 start[0] = stop[0] = x ? maxs[0] : mins[0];
2485 start[1] = stop[1] = y ? maxs[1] : mins[1];
2487 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2489 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2490 bottom = trace.endpos[2];
2491 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2502 Called by monster program code.
2503 The move will be adjusted for slopes and stairs, but if the move isn't
2504 possible, no move is done and false is returned
2507 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2510 vec3_t oldorg, neworg, end, traceendpos;
2513 prvm_edict_t *enemy;
2517 VectorCopy (ent->fields.client->origin, oldorg);
2518 VectorAdd (ent->fields.client->origin, move, neworg);
2520 // flying monsters don't step up
2521 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2523 // try one move with vertical motion, then one without
2524 for (i=0 ; i<2 ; i++)
2526 VectorAdd (ent->fields.client->origin, move, neworg);
2527 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2528 if (i == 0 && enemy != prog->edicts)
2530 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2536 trace = CL_Move (ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2538 VM_SetTraceGlobals(&trace);
2540 if (trace.fraction == 1)
2542 VectorCopy(trace.endpos, traceendpos);
2543 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2544 return false; // swim monster left water
2546 VectorCopy (traceendpos, ent->fields.client->origin);
2552 if (enemy == prog->edicts)
2559 // push down from a step height above the wished position
2560 neworg[2] += sv_stepheight.value;
2561 VectorCopy (neworg, end);
2562 end[2] -= sv_stepheight.value*2;
2564 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2566 VM_SetTraceGlobals(&trace);
2568 if (trace.startsolid)
2570 neworg[2] -= sv_stepheight.value;
2571 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2573 VM_SetTraceGlobals(&trace);
2574 if (trace.startsolid)
2577 if (trace.fraction == 1)
2579 // if monster had the ground pulled out, go ahead and fall
2580 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2582 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2585 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2589 return false; // walked off an edge
2592 // check point traces down for dangling corners
2593 VectorCopy (trace.endpos, ent->fields.client->origin);
2595 if (!CL_CheckBottom (ent))
2597 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2598 { // entity had floor mostly pulled out from underneath it
2599 // and is trying to correct
2604 VectorCopy (oldorg, ent->fields.client->origin);
2608 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2609 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2611 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2612 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2624 float(float yaw, float dist[, settrace]) walkmove
2627 static void VM_CL_walkmove (void)
2636 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2638 // assume failure if it returns early
2639 PRVM_G_FLOAT(OFS_RETURN) = 0;
2641 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2642 if (ent == prog->edicts)
2644 VM_Warning("walkmove: can not modify world entity\n");
2647 if (ent->priv.server->free)
2649 VM_Warning("walkmove: can not modify free entity\n");
2652 yaw = PRVM_G_FLOAT(OFS_PARM0);
2653 dist = PRVM_G_FLOAT(OFS_PARM1);
2654 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2656 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2659 yaw = yaw*M_PI*2 / 360;
2661 move[0] = cos(yaw)*dist;
2662 move[1] = sin(yaw)*dist;
2665 // save program state, because CL_movestep may call other progs
2666 oldf = prog->xfunction;
2667 oldself = prog->globals.client->self;
2669 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2672 // restore program state
2673 prog->xfunction = oldf;
2674 prog->globals.client->self = oldself;
2681 string(string key) serverkey
2684 void VM_CL_serverkey(void)
2686 char string[VM_STRINGTEMP_LENGTH];
2687 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2688 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2689 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2692 //============================================================================
2694 prvm_builtin_t vm_cl_builtins[] = {
2695 NULL, // #0 NULL function (not callable) (QUAKE)
2696 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2697 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2698 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2699 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2700 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2701 VM_break, // #6 void() break (QUAKE)
2702 VM_random, // #7 float() random (QUAKE)
2703 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2704 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2705 VM_error, // #10 void(string e) error (QUAKE)
2706 VM_objerror, // #11 void(string e) objerror (QUAKE)
2707 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2708 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2709 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2710 VM_remove, // #15 void(entity e) remove (QUAKE)
2711 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2712 NULL, // #17 entity() checkclient (QUAKE)
2713 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2714 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2715 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2716 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2717 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2718 NULL, // #23 void(string s, ...) bprint (QUAKE)
2719 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2720 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2721 VM_ftos, // #26 string(float f) ftos (QUAKE)
2722 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2723 VM_coredump, // #28 void() coredump (QUAKE)
2724 VM_traceon, // #29 void() traceon (QUAKE)
2725 VM_traceoff, // #30 void() traceoff (QUAKE)
2726 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2727 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2728 NULL, // #33 (QUAKE)
2729 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2730 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2731 VM_rint, // #36 float(float v) rint (QUAKE)
2732 VM_floor, // #37 float(float v) floor (QUAKE)
2733 VM_ceil, // #38 float(float v) ceil (QUAKE)
2734 NULL, // #39 (QUAKE)
2735 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2736 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2737 NULL, // #42 (QUAKE)
2738 VM_fabs, // #43 float(float f) fabs (QUAKE)
2739 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2740 VM_cvar, // #45 float(string s) cvar (QUAKE)
2741 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2742 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2743 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2744 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2745 NULL, // #50 (QUAKE)
2746 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2747 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2748 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2749 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2750 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2751 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2752 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2753 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2754 NULL, // #59 (QUAKE)
2755 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2756 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2757 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2758 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2759 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2760 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2761 NULL, // #66 (QUAKE)
2762 NULL, // #67 void(float step) movetogoal (QUAKE)
2763 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2764 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2765 NULL, // #70 void(string s) changelevel (QUAKE)
2766 NULL, // #71 (QUAKE)
2767 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2768 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2769 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2770 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2771 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2772 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2773 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2774 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2775 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2776 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2777 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2778 NULL, // #83 (QUAKE)
2779 NULL, // #84 (QUAKE)
2780 NULL, // #85 (QUAKE)
2781 NULL, // #86 (QUAKE)
2782 NULL, // #87 (QUAKE)
2783 NULL, // #88 (QUAKE)
2784 NULL, // #89 (QUAKE)
2785 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2786 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2787 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2788 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2789 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2790 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2791 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2792 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2793 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2794 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2795 // FrikaC and Telejano range #100-#199
2806 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2807 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2808 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2809 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2810 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2811 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2812 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2813 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2814 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2815 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2896 // FTEQW range #200-#299
2915 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2919 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2920 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2925 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2929 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2997 // CSQC range #300-#399
2998 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
2999 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3000 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3001 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3002 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3003 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3004 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3005 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3006 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3008 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3009 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3013 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3014 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3015 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3016 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3017 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3018 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3019 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3020 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3021 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3022 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3023 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3028 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3029 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3030 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3031 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3032 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3033 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3034 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3035 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3036 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3037 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3038 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3039 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3040 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3041 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3042 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3043 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3044 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3045 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3046 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3047 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3048 VM_isserver, // #350 float() isserver (EXT_CSQC)
3049 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3050 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3051 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3052 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3058 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3059 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3060 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3061 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3062 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3063 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3064 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3065 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3098 // LordHavoc's range #400-#499
3099 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3100 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3101 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3102 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3103 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3104 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3105 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3106 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3107 VM_CL_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3108 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3109 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3110 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3111 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3112 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3113 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3114 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3115 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3116 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3117 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3118 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3119 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3120 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3121 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3122 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3123 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3124 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3125 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3126 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3127 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3128 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3129 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3130 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3131 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3132 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3133 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3134 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3135 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3136 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3137 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3138 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3139 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3140 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3141 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3142 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3143 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3144 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3145 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3146 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3147 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3148 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3149 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3150 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3151 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3152 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3153 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3154 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3155 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3156 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3158 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3159 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3160 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3161 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3162 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3163 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3164 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3165 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3166 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3167 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3168 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3169 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3170 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3171 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3172 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3173 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3174 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3175 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3176 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3177 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3178 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3179 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3180 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3181 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3201 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3203 void VM_CL_Cmd_Init(void)
3205 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3206 if(vm_polygons_initialized)
3208 Mem_FreePool(&vm_polygons_pool);
3209 vm_polygons_initialized = false;
3213 void VM_CL_Cmd_Reset(void)
3215 if(vm_polygons_initialized)
3217 Mem_FreePool(&vm_polygons_pool);
3218 vm_polygons_initialized = false;