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 r_view.ortho_x = scr_fov.value * (3.0 / 4.0) * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
635 r_view.ortho_y = scr_fov.value * (3.0 / 4.0);
636 // FIXME: restore cl.csqc_origin
637 // FIXME: restore cl.csqc_angles
638 cl.csqc_vidvars.drawworld = true;
639 cl.csqc_vidvars.drawenginesbar = false;
640 cl.csqc_vidvars.drawcrosshair = false;
643 //#301 void(float mask) addentities (EXT_CSQC)
644 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
645 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
646 static void VM_CL_R_AddEntities (void)
650 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
651 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
652 CSQC_RelinkAllEntities(drawmask);
653 CL_RelinkLightFlashes();
655 prog->globals.client->time = cl.time;
656 for(i=1;i<prog->num_edicts;i++)
658 ed = &prog->edicts[i];
659 if(ed->priv.required->free)
662 if(ed->priv.required->free)
664 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
666 if(ed->priv.required->free)
668 if(!((int)ed->fields.client->drawmask & drawmask))
670 CSQC_AddRenderEdict(ed);
674 //#302 void(entity ent) addentity (EXT_CSQC)
675 static void VM_CL_R_AddEntity (void)
677 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
678 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
681 //#303 float(float property, ...) setproperty (EXT_CSQC)
682 static void VM_CL_R_SetView (void)
688 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
690 c = (int)PRVM_G_FLOAT(OFS_PARM0);
691 f = PRVM_G_VECTOR(OFS_PARM1);
692 k = PRVM_G_FLOAT(OFS_PARM1);
696 case VF_MIN: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
697 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
699 case VF_MIN_X: r_view.x = (int)(k * vid.width / vid_conwidth.value);
701 case VF_MIN_Y: r_view.y = (int)(k * vid.height / vid_conheight.value);
703 case VF_SIZE: r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
704 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
706 case VF_SIZE_Y: r_view.width = (int)(k * vid.width / vid_conwidth.value);
708 case VF_SIZE_X: r_view.height = (int)(k * vid.height / vid_conheight.value);
710 case VF_VIEWPORT: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
711 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
712 f = PRVM_G_VECTOR(OFS_PARM2);
713 r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
714 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
716 case VF_FOV: r_view.frustum_x = tan(f[0] * M_PI / 360.0);r_view.ortho_x = f[0];
717 r_view.frustum_y = tan(f[1] * M_PI / 360.0);r_view.ortho_y = f[1];
719 case VF_FOVX: r_view.frustum_x = tan(k * M_PI / 360.0);r_view.ortho_x = k;
721 case VF_FOVY: r_view.frustum_y = tan(k * M_PI / 360.0);r_view.ortho_y = k;
723 case VF_ORIGIN: VectorCopy(f, cl.csqc_origin);
726 case VF_ORIGIN_X: cl.csqc_origin[0] = k;
729 case VF_ORIGIN_Y: cl.csqc_origin[1] = k;
732 case VF_ORIGIN_Z: cl.csqc_origin[2] = k;
735 case VF_ANGLES: VectorCopy(f, cl.csqc_angles);
738 case VF_ANGLES_X: cl.csqc_angles[0] = k;
741 case VF_ANGLES_Y: cl.csqc_angles[1] = k;
744 case VF_ANGLES_Z: cl.csqc_angles[2] = k;
747 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
749 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
751 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
754 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
756 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
758 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
760 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
763 case VF_PERSPECTIVE: r_view.useperspective = k != 0;
766 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
767 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
770 PRVM_G_FLOAT(OFS_RETURN) = 1;
773 //#304 void() renderscene (EXT_CSQC)
774 static void VM_CL_R_RenderScene (void)
776 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
777 // we need to update any RENDER_VIEWMODEL entities at this point because
778 // csqc supplies its own view matrix
779 CL_UpdateViewEntities();
784 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
785 static void VM_CL_R_AddDynamicLight (void)
789 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
791 // if we've run out of dlights, just return
792 if (r_refdef.numlights >= MAX_DLIGHTS)
795 pos = PRVM_G_VECTOR(OFS_PARM0);
796 col = PRVM_G_VECTOR(OFS_PARM2);
797 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
798 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);
801 //============================================================================
803 //#310 vector (vector v) cs_unproject (EXT_CSQC)
804 static void VM_CL_unproject (void)
809 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
810 f = PRVM_G_VECTOR(OFS_PARM0);
811 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);
812 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
815 //#311 vector (vector v) cs_project (EXT_CSQC)
816 static void VM_CL_project (void)
822 VM_SAFEPARMCOUNT(1, VM_CL_project);
823 f = PRVM_G_VECTOR(OFS_PARM0);
824 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
825 Matrix4x4_Transform(&m, f, v);
826 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]);
829 //#330 float(float stnum) getstatf (EXT_CSQC)
830 static void VM_CL_getstatf (void)
838 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
839 i = (int)PRVM_G_FLOAT(OFS_PARM0);
840 if(i < 0 || i >= MAX_CL_STATS)
842 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
846 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
849 //#331 float(float stnum) getstati (EXT_CSQC)
850 static void VM_CL_getstati (void)
853 VM_SAFEPARMCOUNT(1, VM_CL_getstati);
854 index = (int)PRVM_G_FLOAT(OFS_PARM0);
856 if(index < 0 || index >= MAX_CL_STATS)
858 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
862 PRVM_G_FLOAT(OFS_RETURN) = i;
865 //#332 string(float firststnum) getstats (EXT_CSQC)
866 static void VM_CL_getstats (void)
870 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
871 i = (int)PRVM_G_FLOAT(OFS_PARM0);
872 if(i < 0 || i > MAX_CL_STATS-4)
874 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
875 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
878 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
879 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
882 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
883 static void VM_CL_setmodelindex (void)
887 struct model_s *model;
889 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
891 t = PRVM_G_EDICT(OFS_PARM0);
893 i = (int)PRVM_G_FLOAT(OFS_PARM1);
895 t->fields.client->model = 0;
896 t->fields.client->modelindex = 0;
901 model = CL_GetModelByIndex(i);
904 VM_Warning("VM_CL_setmodelindex: null model\n");
907 t->fields.client->model = PRVM_SetEngineString(model->name);
908 t->fields.client->modelindex = i;
911 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
912 static void VM_CL_modelnameforindex (void)
916 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
918 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
919 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
920 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
923 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
924 static void VM_CL_particleeffectnum (void)
927 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
928 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
931 PRVM_G_FLOAT(OFS_RETURN) = i;
934 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
935 static void VM_CL_trailparticles (void)
940 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
942 t = PRVM_G_EDICT(OFS_PARM0);
943 i = (int)PRVM_G_FLOAT(OFS_PARM1);
944 start = PRVM_G_VECTOR(OFS_PARM2);
945 end = PRVM_G_VECTOR(OFS_PARM3);
947 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);
950 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
951 static void VM_CL_pointparticles (void)
955 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
956 i = (int)PRVM_G_FLOAT(OFS_PARM0);
957 f = PRVM_G_VECTOR(OFS_PARM1);
958 v = PRVM_G_VECTOR(OFS_PARM2);
959 n = (int)PRVM_G_FLOAT(OFS_PARM3);
960 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
963 //#342 string(float keynum) getkeybind (EXT_CSQC)
964 static void VM_CL_getkeybind (void)
966 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
967 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
970 //#343 void(float usecursor) setcursormode (EXT_CSQC)
971 static void VM_CL_setcursormode (void)
973 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
974 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
975 cl_ignoremousemove = true;
978 //#345 float(float framenum) getinputstate (EXT_CSQC)
979 static void VM_CL_getinputstate (void)
982 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
983 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
984 for (i = 0;i < cl.movement_numqueue;i++)
985 if (cl.movement_queue[i].sequence == frame)
987 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
988 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
989 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
990 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
991 if(cl.movement_queue[i].crouch)
993 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
994 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
998 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
999 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1004 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1005 static void VM_CL_setsensitivityscale (void)
1007 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1008 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1011 //#347 void() runstandardplayerphysics (EXT_CSQC)
1012 static void VM_CL_runplayerphysics (void)
1016 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1017 static void VM_CL_getplayerkey (void)
1023 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1025 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1026 c = PRVM_G_STRING(OFS_PARM1);
1027 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1030 i = Sbar_GetPlayer(i);
1036 if(!strcasecmp(c, "name"))
1037 strlcpy(t, cl.scores[i].name, sizeof(t));
1039 if(!strcasecmp(c, "frags"))
1040 sprintf(t, "%i", cl.scores[i].frags);
1042 if(!strcasecmp(c, "ping"))
1043 sprintf(t, "%i", cl.scores[i].qw_ping);
1045 if(!strcasecmp(c, "entertime"))
1046 sprintf(t, "%f", cl.scores[i].qw_entertime);
1048 if(!strcasecmp(c, "colors"))
1049 sprintf(t, "%i", cl.scores[i].colors);
1051 if(!strcasecmp(c, "topcolor"))
1052 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1054 if(!strcasecmp(c, "bottomcolor"))
1055 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1057 if(!strcasecmp(c, "viewentity"))
1058 sprintf(t, "%i", i+1);
1061 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1064 //#349 float() isdemo (EXT_CSQC)
1065 static void VM_CL_isdemo (void)
1067 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1068 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1071 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1072 static void VM_CL_setlistener (void)
1074 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1075 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));
1076 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1079 //#352 void(string cmdname) registercommand (EXT_CSQC)
1080 static void VM_CL_registercmd (void)
1083 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1084 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1088 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1089 t = (char *)Z_Malloc(alloclen);
1090 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1091 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1094 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1098 //#360 float() readbyte (EXT_CSQC)
1099 static void VM_CL_ReadByte (void)
1101 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1102 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1105 //#361 float() readchar (EXT_CSQC)
1106 static void VM_CL_ReadChar (void)
1108 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1109 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1112 //#362 float() readshort (EXT_CSQC)
1113 static void VM_CL_ReadShort (void)
1115 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1116 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1119 //#363 float() readlong (EXT_CSQC)
1120 static void VM_CL_ReadLong (void)
1122 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1123 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1126 //#364 float() readcoord (EXT_CSQC)
1127 static void VM_CL_ReadCoord (void)
1129 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1130 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1133 //#365 float() readangle (EXT_CSQC)
1134 static void VM_CL_ReadAngle (void)
1136 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1137 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1140 //#366 string() readstring (EXT_CSQC)
1141 static void VM_CL_ReadString (void)
1143 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1144 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1147 //#367 float() readfloat (EXT_CSQC)
1148 static void VM_CL_ReadFloat (void)
1150 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1151 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1154 //////////////////////////////////////////////////////////
1156 static void VM_CL_makestatic (void)
1160 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1162 ent = PRVM_G_EDICT(OFS_PARM0);
1163 if (ent == prog->edicts)
1165 VM_Warning("makestatic: can not modify world entity\n");
1168 if (ent->priv.server->free)
1170 VM_Warning("makestatic: can not modify free entity\n");
1174 if (cl.num_static_entities < cl.max_static_entities)
1178 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1180 // copy it to the current state
1181 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1182 staticent->render.frame = staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1183 staticent->render.framelerp = 0;
1184 // make torchs play out of sync
1185 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1186 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1187 staticent->render.skinnum = (int)ent->fields.client->skin;
1188 staticent->render.effects = (int)ent->fields.client->effects;
1189 staticent->render.alpha = 1;
1190 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1191 staticent->render.scale = 1;
1192 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1193 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1196 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1197 if (renderflags & RF_USEAXIS)
1200 VectorNegate(prog->globals.client->v_right, left);
1201 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1202 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1205 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);
1206 CL_UpdateRenderEntity(&staticent->render);
1208 // either fullbright or lit
1209 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1210 staticent->render.flags |= RENDER_LIGHT;
1211 // turn off shadows from transparent objects
1212 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1213 staticent->render.flags |= RENDER_SHADOW;
1216 Con_Printf("Too many static entities");
1218 // throw the entity away now
1222 //=================================================================//
1228 copies data from one entity to another
1230 copyentity(src, dst)
1233 static void VM_CL_copyentity (void)
1235 prvm_edict_t *in, *out;
1236 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1237 in = PRVM_G_EDICT(OFS_PARM0);
1238 if (in == prog->edicts)
1240 VM_Warning("copyentity: can not read world entity\n");
1243 if (in->priv.server->free)
1245 VM_Warning("copyentity: can not read free entity\n");
1248 out = PRVM_G_EDICT(OFS_PARM1);
1249 if (out == prog->edicts)
1251 VM_Warning("copyentity: can not modify world entity\n");
1254 if (out->priv.server->free)
1256 VM_Warning("copyentity: can not modify free entity\n");
1259 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1263 //=================================================================//
1265 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1266 static void VM_CL_effect (void)
1268 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1269 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));
1272 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1273 static void VM_CL_te_blood (void)
1277 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1278 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1280 pos = PRVM_G_VECTOR(OFS_PARM0);
1281 CL_FindNonSolidLocation(pos, pos2, 4);
1282 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1285 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1286 static void VM_CL_te_bloodshower (void)
1290 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1291 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1293 speed = PRVM_G_FLOAT(OFS_PARM2);
1300 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1303 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1304 static void VM_CL_te_explosionrgb (void)
1308 matrix4x4_t tempmatrix;
1309 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1310 pos = PRVM_G_VECTOR(OFS_PARM0);
1311 CL_FindNonSolidLocation(pos, pos2, 10);
1312 CL_ParticleExplosion(pos2);
1313 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1314 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);
1317 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1318 static void VM_CL_te_particlecube (void)
1320 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1321 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));
1324 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1325 static void VM_CL_te_particlerain (void)
1327 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1328 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);
1331 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1332 static void VM_CL_te_particlesnow (void)
1334 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1335 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);
1338 // #411 void(vector org, vector vel, float howmany) te_spark
1339 static void VM_CL_te_spark (void)
1343 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1345 pos = PRVM_G_VECTOR(OFS_PARM0);
1346 CL_FindNonSolidLocation(pos, pos2, 4);
1347 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1350 extern cvar_t cl_sound_ric_gunshot;
1351 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1352 static void VM_CL_te_gunshotquad (void)
1357 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1359 pos = PRVM_G_VECTOR(OFS_PARM0);
1360 CL_FindNonSolidLocation(pos, pos2, 4);
1361 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1362 if(cl_sound_ric_gunshot.integer >= 2)
1364 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1368 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1369 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1370 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1375 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1376 static void VM_CL_te_spikequad (void)
1381 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1383 pos = PRVM_G_VECTOR(OFS_PARM0);
1384 CL_FindNonSolidLocation(pos, pos2, 4);
1385 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1386 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1390 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1391 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1392 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1396 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1397 static void VM_CL_te_superspikequad (void)
1402 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1404 pos = PRVM_G_VECTOR(OFS_PARM0);
1405 CL_FindNonSolidLocation(pos, pos2, 4);
1406 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1407 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1411 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1412 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1413 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1417 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1418 static void VM_CL_te_explosionquad (void)
1422 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1424 pos = PRVM_G_VECTOR(OFS_PARM0);
1425 CL_FindNonSolidLocation(pos, pos2, 10);
1426 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1427 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1430 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1431 static void VM_CL_te_smallflash (void)
1435 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1437 pos = PRVM_G_VECTOR(OFS_PARM0);
1438 CL_FindNonSolidLocation(pos, pos2, 10);
1439 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1442 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1443 static void VM_CL_te_customflash (void)
1447 matrix4x4_t tempmatrix;
1448 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1450 pos = PRVM_G_VECTOR(OFS_PARM0);
1451 CL_FindNonSolidLocation(pos, pos2, 4);
1452 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1453 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);
1456 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1457 static void VM_CL_te_gunshot (void)
1462 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1464 pos = PRVM_G_VECTOR(OFS_PARM0);
1465 CL_FindNonSolidLocation(pos, pos2, 4);
1466 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1467 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1469 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1473 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1474 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1475 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1480 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1481 static void VM_CL_te_spike (void)
1486 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1488 pos = PRVM_G_VECTOR(OFS_PARM0);
1489 CL_FindNonSolidLocation(pos, pos2, 4);
1490 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1491 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1495 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1496 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1497 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1501 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1502 static void VM_CL_te_superspike (void)
1507 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1509 pos = PRVM_G_VECTOR(OFS_PARM0);
1510 CL_FindNonSolidLocation(pos, pos2, 4);
1511 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1512 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1516 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1517 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1518 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1522 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1523 static void VM_CL_te_explosion (void)
1527 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1529 pos = PRVM_G_VECTOR(OFS_PARM0);
1530 CL_FindNonSolidLocation(pos, pos2, 10);
1531 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1532 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1535 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1536 static void VM_CL_te_tarexplosion (void)
1540 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1542 pos = PRVM_G_VECTOR(OFS_PARM0);
1543 CL_FindNonSolidLocation(pos, pos2, 10);
1544 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1545 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1548 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1549 static void VM_CL_te_wizspike (void)
1553 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1555 pos = PRVM_G_VECTOR(OFS_PARM0);
1556 CL_FindNonSolidLocation(pos, pos2, 4);
1557 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1558 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1561 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1562 static void VM_CL_te_knightspike (void)
1566 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1568 pos = PRVM_G_VECTOR(OFS_PARM0);
1569 CL_FindNonSolidLocation(pos, pos2, 4);
1570 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1571 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1574 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1575 static void VM_CL_te_lavasplash (void)
1577 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1578 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1581 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1582 static void VM_CL_te_teleport (void)
1584 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1585 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1588 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1589 static void VM_CL_te_explosion2 (void)
1593 matrix4x4_t tempmatrix;
1594 int colorStart, colorLength;
1595 unsigned char *tempcolor;
1596 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1598 pos = PRVM_G_VECTOR(OFS_PARM0);
1599 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1600 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1601 CL_FindNonSolidLocation(pos, pos2, 10);
1602 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1603 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1604 color[0] = tempcolor[0] * (2.0f / 255.0f);
1605 color[1] = tempcolor[1] * (2.0f / 255.0f);
1606 color[2] = tempcolor[2] * (2.0f / 255.0f);
1607 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1608 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);
1609 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1613 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1614 static void VM_CL_te_lightning1 (void)
1616 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1617 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1620 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1621 static void VM_CL_te_lightning2 (void)
1623 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1624 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1627 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1628 static void VM_CL_te_lightning3 (void)
1630 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1631 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1634 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1635 static void VM_CL_te_beam (void)
1637 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1638 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1641 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1642 static void VM_CL_te_plasmaburn (void)
1646 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1648 pos = PRVM_G_VECTOR(OFS_PARM0);
1649 CL_FindNonSolidLocation(pos, pos2, 4);
1650 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1653 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1654 static void VM_CL_te_flamejet (void)
1658 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1659 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1661 pos = PRVM_G_VECTOR(OFS_PARM0);
1662 CL_FindNonSolidLocation(pos, pos2, 4);
1663 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1667 //====================================================================
1670 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1672 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1674 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1676 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1679 // #434 float(entity e, float s) getsurfacenumpoints
1680 static void VM_CL_getsurfacenumpoints(void)
1683 msurface_t *surface;
1684 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1685 // return 0 if no such surface
1686 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1688 PRVM_G_FLOAT(OFS_RETURN) = 0;
1692 // note: this (incorrectly) assumes it is a simple polygon
1693 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1696 // #435 vector(entity e, float s, float n) getsurfacepoint
1697 static void VM_CL_getsurfacepoint(void)
1701 msurface_t *surface;
1703 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1704 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1705 ed = PRVM_G_EDICT(OFS_PARM0);
1706 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1708 // note: this (incorrectly) assumes it is a simple polygon
1709 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1710 if (pointnum < 0 || pointnum >= surface->num_vertices)
1712 // FIXME: implement rotation/scaling
1713 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1716 // #436 vector(entity e, float s) getsurfacenormal
1717 static void VM_CL_getsurfacenormal(void)
1720 msurface_t *surface;
1722 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1723 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1724 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1726 // FIXME: implement rotation/scaling
1727 // note: this (incorrectly) assumes it is a simple polygon
1728 // note: this only returns the first triangle, so it doesn't work very
1729 // well for curved surfaces or arbitrary meshes
1730 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);
1731 VectorNormalize(normal);
1732 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1735 // #437 string(entity e, float s) getsurfacetexture
1736 static void VM_CL_getsurfacetexture(void)
1739 msurface_t *surface;
1740 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1741 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1742 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1744 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1747 // #438 float(entity e, vector p) getsurfacenearpoint
1748 static void VM_CL_getsurfacenearpoint(void)
1750 int surfacenum, best;
1752 vec_t dist, bestdist;
1754 model_t *model = NULL;
1755 msurface_t *surface;
1757 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1758 PRVM_G_FLOAT(OFS_RETURN) = -1;
1759 ed = PRVM_G_EDICT(OFS_PARM0);
1760 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1763 // FIXME: implement rotation/scaling
1764 point = PRVM_G_VECTOR(OFS_PARM1);
1765 VectorSubtract(point, ed->fields.client->origin, p);
1767 bestdist = 1000000000;
1768 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1770 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1771 // first see if the nearest point on the surface's box is closer than the previous match
1772 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1773 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1774 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1775 dist = VectorLength2(clipped);
1776 if (dist < bestdist)
1778 // it is, check the nearest point on the actual geometry
1779 clippointtosurface(model, surface, p, clipped);
1780 VectorSubtract(clipped, p, clipped);
1781 dist += VectorLength2(clipped);
1782 if (dist < bestdist)
1784 // that's closer too, store it as the best match
1790 PRVM_G_FLOAT(OFS_RETURN) = best;
1793 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1794 static void VM_CL_getsurfaceclippedpoint(void)
1798 msurface_t *surface;
1800 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1801 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1802 ed = PRVM_G_EDICT(OFS_PARM0);
1803 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1805 // FIXME: implement rotation/scaling
1806 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1807 clippointtosurface(model, surface, p, out);
1808 // FIXME: implement rotation/scaling
1809 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1812 // #443 void(entity e, entity tagentity, string tagname) setattachment
1813 static void VM_CL_setattachment (void)
1816 prvm_edict_t *tagentity;
1817 const char *tagname;
1821 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1823 e = PRVM_G_EDICT(OFS_PARM0);
1824 tagentity = PRVM_G_EDICT(OFS_PARM1);
1825 tagname = PRVM_G_STRING(OFS_PARM2);
1827 if (e == prog->edicts)
1829 VM_Warning("setattachment: can not modify world entity\n");
1832 if (e->priv.server->free)
1834 VM_Warning("setattachment: can not modify free entity\n");
1838 if (tagentity == NULL)
1839 tagentity = prog->edicts;
1841 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1843 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1845 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1848 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1850 modelindex = (int)tagentity->fields.client->modelindex;
1851 model = CL_GetModelByIndex(modelindex);
1854 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1856 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);
1859 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));
1863 /////////////////////////////////////////
1864 // DP_MD3_TAGINFO extension coded by VorteX
1866 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1868 model_t *model = CL_GetModelFromEdict(e);
1870 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1875 // Warnings/errors code:
1876 // 0 - normal (everything all-right)
1879 // 3 - null or non-precached model
1880 // 4 - no tags with requested index
1881 // 5 - runaway loop at attachment chain
1882 extern cvar_t cl_bob;
1883 extern cvar_t cl_bobcycle;
1884 extern cvar_t cl_bobup;
1885 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1888 int reqframe, attachloop;
1889 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1890 prvm_edict_t *attachent;
1893 *out = identitymatrix; // warnings and errors return identical matrix
1895 if (ent == prog->edicts)
1897 if (ent->priv.server->free)
1900 model = CL_GetModelFromEdict(ent);
1905 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1906 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1908 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1910 // get initial tag matrix
1913 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1918 tagmatrix = identitymatrix;
1920 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1921 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1925 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1926 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1928 model = CL_GetModelFromEdict(attachent);
1930 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1931 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1933 attachmatrix = identitymatrix;
1935 // apply transformation by child entity matrix
1936 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1937 if (val->_float == 0)
1939 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);
1940 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1941 Matrix4x4_Copy(&tagmatrix, out);
1943 // finally transformate by matrix of tag on parent entity
1944 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1945 Matrix4x4_Copy(&tagmatrix, out);
1949 if (attachloop > 255) // prevent runaway looping
1952 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1955 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1956 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1957 if (val->_float == 0)
1959 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1960 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);
1961 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1963 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1964 {// RENDER_VIEWMODEL magic
1965 Matrix4x4_Copy(&tagmatrix, out);
1967 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1968 if (val->_float == 0)
1971 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);
1972 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1975 // Cl_bob, ported from rendering code
1976 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
1979 // LordHavoc: this code is *weird*, but not replacable (I think it
1980 // should be done in QC on the server, but oh well, quake is quake)
1981 // LordHavoc: figured out bobup: the time at which the sin is at 180
1982 // degrees (which allows lengthening or squishing the peak or valley)
1983 cycle = cl.time/cl_bobcycle.value;
1984 cycle -= (int)cycle;
1985 if (cycle < cl_bobup.value)
1986 cycle = sin(M_PI * cycle / cl_bobup.value);
1988 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
1989 // bob is proportional to velocity in the xy plane
1990 // (don't count Z, or jumping messes it up)
1991 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;
1992 bob = bob*0.3 + bob*0.7*cycle;
1993 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2000 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2001 static void VM_CL_gettagindex (void)
2004 const char *tag_name;
2005 int modelindex, tag_index;
2007 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2009 ent = PRVM_G_EDICT(OFS_PARM0);
2010 tag_name = PRVM_G_STRING(OFS_PARM1);
2011 if (ent == prog->edicts)
2013 VM_Warning("gettagindex: can't affect world entity\n");
2016 if (ent->priv.server->free)
2018 VM_Warning("gettagindex: can't affect free entity\n");
2022 modelindex = (int)ent->fields.client->modelindex;
2024 modelindex = -(modelindex+1);
2026 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2027 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2030 tag_index = CL_GetTagIndex(ent, tag_name);
2032 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2034 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2037 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2038 static void VM_CL_gettaginfo (void)
2042 matrix4x4_t tag_matrix;
2045 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2047 e = PRVM_G_EDICT(OFS_PARM0);
2048 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2049 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2050 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2055 VM_Warning("gettagindex: can't affect world entity\n");
2058 VM_Warning("gettagindex: can't affect free entity\n");
2061 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2064 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2067 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2072 //============================================================================
2074 //====================
2075 //QC POLYGON functions
2076 //====================
2081 float data[36]; //[515]: enough for polygons
2082 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2085 //static float vm_polygon_linewidth = 1;
2086 static mempool_t *vm_polygons_pool = NULL;
2087 static unsigned char vm_current_vertices = 0;
2088 static qboolean vm_polygons_initialized = false;
2089 static vm_polygon_t *vm_polygons = NULL;
2090 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2091 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2092 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2094 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2095 #define VM_POLYGON_FLLINES 32
2096 #define VM_POLYGON_FL2D 64
2097 #define VM_POLYGON_FL4V 128 //4 vertices
2099 static void VM_InitPolygons (void)
2101 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2102 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2103 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2104 vm_polygons_num = VM_DEFPOLYNUM;
2105 vm_drawpolygons_num = 0;
2106 vm_polygonbegin = false;
2107 vm_polygons_initialized = true;
2110 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2112 int surfacelistindex;
2113 // LordHavoc: FIXME: this is stupid code
2114 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2116 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2117 int flags = p->flags & 0x0f;
2119 if(flags == DRAWFLAG_ADDITIVE)
2120 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2121 else if(flags == DRAWFLAG_MODULATE)
2122 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2123 else if(flags == DRAWFLAG_2XMODULATE)
2124 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2126 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2128 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2131 //[515]: is speed is max ?
2132 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2134 qglLineWidth(p->data[13]);CHECKGLERROR
2135 qglBegin(GL_LINE_LOOP);
2136 qglTexCoord1f (p->data[12]);
2137 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2138 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2140 qglTexCoord1f (p->data[14]);
2141 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2142 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2144 if(p->flags & VM_POLYGON_FL3V)
2146 qglTexCoord1f (p->data[16]);
2147 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2148 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2150 if(p->flags & VM_POLYGON_FL4V)
2152 qglTexCoord1f (p->data[18]);
2153 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2154 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2162 qglBegin(GL_POLYGON);
2163 qglTexCoord2f (p->data[12], p->data[13]);
2164 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2165 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2167 qglTexCoord2f (p->data[14], p->data[15]);
2168 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2169 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2171 qglTexCoord2f (p->data[16], p->data[17]);
2172 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2173 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2175 if(p->flags & VM_POLYGON_FL4V)
2177 qglTexCoord2f (p->data[18], p->data[19]);
2178 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2179 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2187 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2189 drawqueuemesh_t mesh;
2190 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2192 mesh.texture = p->tex;
2193 mesh.data_element3i = picelements;
2194 mesh.data_vertex3f = p->data;
2195 mesh.data_texcoord2f = p->data + 12;
2196 mesh.data_color4f = p->data + 20;
2197 if(p->flags & VM_POLYGON_FL4V)
2199 mesh.num_vertices = 4;
2200 mesh.num_triangles = 2;
2204 mesh.num_vertices = 3;
2205 mesh.num_triangles = 1;
2207 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2208 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2210 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2213 void VM_CL_AddPolygonsToMeshQueue (void)
2216 if(!vm_drawpolygons_num)
2218 R_Mesh_Matrix(&identitymatrix);
2219 GL_CullFace(GL_NONE);
2220 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2221 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2222 vm_drawpolygons_num = 0;
2225 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2226 static void VM_CL_R_PolygonBegin (void)
2229 const char *picname;
2230 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2232 if(!vm_polygons_initialized)
2236 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2239 if(vm_drawpolygons_num >= vm_polygons_num)
2241 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2242 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2243 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2244 Mem_Free(vm_polygons);
2246 vm_polygons_num *= 2;
2248 p = &vm_polygons[vm_drawpolygons_num];
2249 picname = PRVM_G_STRING(OFS_PARM0);
2251 p->tex = Draw_CachePic(picname, true)->tex;
2253 p->tex = r_texture_white;
2254 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2255 vm_current_vertices = 0;
2256 vm_polygonbegin = true;
2259 if(PRVM_G_FLOAT(OFS_PARM2))
2260 p->flags |= VM_POLYGON_FL2D;
2261 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2263 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2264 p->flags |= VM_POLYGON_FLLINES;
2269 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2270 static void VM_CL_R_PolygonVertex (void)
2272 float *coords, *tx, *rgb, alpha;
2274 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2276 if(!vm_polygonbegin)
2278 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2281 coords = PRVM_G_VECTOR(OFS_PARM0);
2282 tx = PRVM_G_VECTOR(OFS_PARM1);
2283 rgb = PRVM_G_VECTOR(OFS_PARM2);
2284 alpha = PRVM_G_FLOAT(OFS_PARM3);
2286 p = &vm_polygons[vm_drawpolygons_num];
2287 if(vm_current_vertices > 4)
2289 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2293 p->data[vm_current_vertices*3] = coords[0];
2294 p->data[1+vm_current_vertices*3] = coords[1];
2295 p->data[2+vm_current_vertices*3] = coords[2];
2297 p->data[12+vm_current_vertices*2] = tx[0];
2298 if(!(p->flags & VM_POLYGON_FLLINES))
2299 p->data[13+vm_current_vertices*2] = tx[1];
2301 p->data[20+vm_current_vertices*4] = rgb[0];
2302 p->data[21+vm_current_vertices*4] = rgb[1];
2303 p->data[22+vm_current_vertices*4] = rgb[2];
2304 p->data[23+vm_current_vertices*4] = alpha;
2306 vm_current_vertices++;
2307 if(vm_current_vertices == 4)
2308 p->flags |= VM_POLYGON_FL4V;
2310 if(vm_current_vertices == 3)
2311 p->flags |= VM_POLYGON_FL3V;
2314 //void() R_EndPolygon
2315 static void VM_CL_R_PolygonEnd (void)
2317 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2318 if(!vm_polygonbegin)
2320 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2323 vm_polygonbegin = false;
2324 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2326 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2327 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2329 vm_drawpolygons_num++;
2332 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2335 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2339 if(!vm_polygons_initialized)
2343 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2346 // limit polygons to a vaguely sane amount, beyond this each one just
2347 // replaces the last one
2348 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2349 if(vm_drawpolygons_num >= vm_polygons_num)
2351 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2352 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2353 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2354 Mem_Free(vm_polygons);
2356 vm_polygons_num *= 2;
2358 p = &vm_polygons[vm_drawpolygons_num];
2359 if(picname && picname[0])
2360 p->tex = Draw_CachePic(picname, true)->tex;
2362 p->tex = r_texture_white;
2364 vm_current_vertices = 0;
2365 vm_polygonbegin = true;
2367 p->flags |= VM_POLYGON_FL2D;
2370 p->data[13] = linewidth; //[515]: linewidth
2371 p->flags |= VM_POLYGON_FLLINES;
2375 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2379 if(!vm_polygonbegin)
2381 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2385 p = &vm_polygons[vm_drawpolygons_num];
2386 if(vm_current_vertices > 4)
2388 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2392 p->data[vm_current_vertices*3] = x;
2393 p->data[1+vm_current_vertices*3] = y;
2394 p->data[2+vm_current_vertices*3] = z;
2396 p->data[12+vm_current_vertices*2] = s;
2397 if(!(p->flags & VM_POLYGON_FLLINES))
2398 p->data[13+vm_current_vertices*2] = t;
2400 p->data[20+vm_current_vertices*4] = r;
2401 p->data[21+vm_current_vertices*4] = g;
2402 p->data[22+vm_current_vertices*4] = b;
2403 p->data[23+vm_current_vertices*4] = a;
2405 vm_current_vertices++;
2406 if(vm_current_vertices == 4)
2407 p->flags |= VM_POLYGON_FL4V;
2409 if(vm_current_vertices == 3)
2410 p->flags |= VM_POLYGON_FL3V;
2413 void Debug_PolygonEnd(void)
2415 if(!vm_polygonbegin)
2417 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2420 vm_polygonbegin = false;
2421 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2423 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2424 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2426 vm_drawpolygons_num++;
2429 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2436 Returns false if any part of the bottom of the entity is off an edge that
2441 qboolean CL_CheckBottom (prvm_edict_t *ent)
2443 vec3_t mins, maxs, start, stop;
2448 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2449 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2451 // if all of the points under the corners are solid world, don't bother
2452 // with the tougher checks
2453 // the corners must be within 16 of the midpoint
2454 start[2] = mins[2] - 1;
2455 for (x=0 ; x<=1 ; x++)
2456 for (y=0 ; y<=1 ; y++)
2458 start[0] = x ? maxs[0] : mins[0];
2459 start[1] = y ? maxs[1] : mins[1];
2460 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2464 return true; // we got out easy
2468 // check it for real...
2472 // the midpoint must be within 16 of the bottom
2473 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2474 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2475 stop[2] = start[2] - 2*sv_stepheight.value;
2476 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2478 if (trace.fraction == 1.0)
2480 mid = bottom = trace.endpos[2];
2482 // the corners must be within 16 of the midpoint
2483 for (x=0 ; x<=1 ; x++)
2484 for (y=0 ; y<=1 ; y++)
2486 start[0] = stop[0] = x ? maxs[0] : mins[0];
2487 start[1] = stop[1] = y ? maxs[1] : mins[1];
2489 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2491 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2492 bottom = trace.endpos[2];
2493 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2504 Called by monster program code.
2505 The move will be adjusted for slopes and stairs, but if the move isn't
2506 possible, no move is done and false is returned
2509 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2512 vec3_t oldorg, neworg, end, traceendpos;
2515 prvm_edict_t *enemy;
2519 VectorCopy (ent->fields.client->origin, oldorg);
2520 VectorAdd (ent->fields.client->origin, move, neworg);
2522 // flying monsters don't step up
2523 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2525 // try one move with vertical motion, then one without
2526 for (i=0 ; i<2 ; i++)
2528 VectorAdd (ent->fields.client->origin, move, neworg);
2529 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2530 if (i == 0 && enemy != prog->edicts)
2532 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2538 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);
2540 VM_SetTraceGlobals(&trace);
2542 if (trace.fraction == 1)
2544 VectorCopy(trace.endpos, traceendpos);
2545 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2546 return false; // swim monster left water
2548 VectorCopy (traceendpos, ent->fields.client->origin);
2554 if (enemy == prog->edicts)
2561 // push down from a step height above the wished position
2562 neworg[2] += sv_stepheight.value;
2563 VectorCopy (neworg, end);
2564 end[2] -= sv_stepheight.value*2;
2566 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2568 VM_SetTraceGlobals(&trace);
2570 if (trace.startsolid)
2572 neworg[2] -= sv_stepheight.value;
2573 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2575 VM_SetTraceGlobals(&trace);
2576 if (trace.startsolid)
2579 if (trace.fraction == 1)
2581 // if monster had the ground pulled out, go ahead and fall
2582 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2584 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2587 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2591 return false; // walked off an edge
2594 // check point traces down for dangling corners
2595 VectorCopy (trace.endpos, ent->fields.client->origin);
2597 if (!CL_CheckBottom (ent))
2599 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2600 { // entity had floor mostly pulled out from underneath it
2601 // and is trying to correct
2606 VectorCopy (oldorg, ent->fields.client->origin);
2610 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2611 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2613 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2614 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2626 float(float yaw, float dist[, settrace]) walkmove
2629 static void VM_CL_walkmove (void)
2638 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2640 // assume failure if it returns early
2641 PRVM_G_FLOAT(OFS_RETURN) = 0;
2643 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2644 if (ent == prog->edicts)
2646 VM_Warning("walkmove: can not modify world entity\n");
2649 if (ent->priv.server->free)
2651 VM_Warning("walkmove: can not modify free entity\n");
2654 yaw = PRVM_G_FLOAT(OFS_PARM0);
2655 dist = PRVM_G_FLOAT(OFS_PARM1);
2656 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2658 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2661 yaw = yaw*M_PI*2 / 360;
2663 move[0] = cos(yaw)*dist;
2664 move[1] = sin(yaw)*dist;
2667 // save program state, because CL_movestep may call other progs
2668 oldf = prog->xfunction;
2669 oldself = prog->globals.client->self;
2671 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2674 // restore program state
2675 prog->xfunction = oldf;
2676 prog->globals.client->self = oldself;
2683 string(string key) serverkey
2686 void VM_CL_serverkey(void)
2688 char string[VM_STRINGTEMP_LENGTH];
2689 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2690 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2691 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2694 //============================================================================
2696 prvm_builtin_t vm_cl_builtins[] = {
2697 NULL, // #0 NULL function (not callable) (QUAKE)
2698 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2699 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2700 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2701 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2702 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2703 VM_break, // #6 void() break (QUAKE)
2704 VM_random, // #7 float() random (QUAKE)
2705 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2706 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2707 VM_error, // #10 void(string e) error (QUAKE)
2708 VM_objerror, // #11 void(string e) objerror (QUAKE)
2709 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2710 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2711 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2712 VM_remove, // #15 void(entity e) remove (QUAKE)
2713 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2714 NULL, // #17 entity() checkclient (QUAKE)
2715 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2716 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2717 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2718 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2719 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2720 NULL, // #23 void(string s, ...) bprint (QUAKE)
2721 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2722 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2723 VM_ftos, // #26 string(float f) ftos (QUAKE)
2724 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2725 VM_coredump, // #28 void() coredump (QUAKE)
2726 VM_traceon, // #29 void() traceon (QUAKE)
2727 VM_traceoff, // #30 void() traceoff (QUAKE)
2728 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2729 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2730 NULL, // #33 (QUAKE)
2731 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2732 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2733 VM_rint, // #36 float(float v) rint (QUAKE)
2734 VM_floor, // #37 float(float v) floor (QUAKE)
2735 VM_ceil, // #38 float(float v) ceil (QUAKE)
2736 NULL, // #39 (QUAKE)
2737 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2738 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2739 NULL, // #42 (QUAKE)
2740 VM_fabs, // #43 float(float f) fabs (QUAKE)
2741 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2742 VM_cvar, // #45 float(string s) cvar (QUAKE)
2743 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2744 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2745 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2746 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2747 NULL, // #50 (QUAKE)
2748 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2749 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2750 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2751 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2752 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2753 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2754 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2755 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2756 NULL, // #59 (QUAKE)
2757 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2758 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2759 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2760 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2761 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2762 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2763 NULL, // #66 (QUAKE)
2764 NULL, // #67 void(float step) movetogoal (QUAKE)
2765 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2766 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2767 NULL, // #70 void(string s) changelevel (QUAKE)
2768 NULL, // #71 (QUAKE)
2769 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2770 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2771 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2772 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2773 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2774 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2775 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2776 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2777 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2778 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2779 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2780 NULL, // #83 (QUAKE)
2781 NULL, // #84 (QUAKE)
2782 NULL, // #85 (QUAKE)
2783 NULL, // #86 (QUAKE)
2784 NULL, // #87 (QUAKE)
2785 NULL, // #88 (QUAKE)
2786 NULL, // #89 (QUAKE)
2787 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2788 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2789 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2790 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2791 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2792 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2793 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2794 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2795 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2796 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2797 // FrikaC and Telejano range #100-#199
2808 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2809 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2810 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2811 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2812 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2813 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2814 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2815 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2816 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2817 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2898 // FTEQW range #200-#299
2917 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2921 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2922 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2927 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2931 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2999 // CSQC range #300-#399
3000 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
3001 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3002 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3003 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3004 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3005 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3006 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3007 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3008 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3010 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3011 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3015 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3016 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3017 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3018 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3019 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3020 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3021 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3022 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3023 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3024 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3025 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3030 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3031 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3032 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3033 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3034 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3035 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3036 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3037 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3038 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3039 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3040 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3041 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3042 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3043 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3044 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3045 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3046 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3047 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3048 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3049 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3050 VM_isserver, // #350 float() isserver (EXT_CSQC)
3051 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3052 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3053 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3054 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3060 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3061 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3062 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3063 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3064 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3065 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3066 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3067 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3100 // LordHavoc's range #400-#499
3101 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3102 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3103 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3104 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3105 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3106 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3107 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3108 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3109 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)
3110 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3111 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3112 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3113 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3114 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3115 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3116 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3117 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3118 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3119 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3120 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3121 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3122 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3123 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3124 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3125 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3126 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3127 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3128 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3129 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3130 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3131 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3132 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3133 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3134 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3135 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3136 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3137 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3138 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3139 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3140 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3141 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3142 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3143 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3144 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3145 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3146 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3147 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3148 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3149 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3150 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3151 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3152 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3153 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3154 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3155 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3156 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3157 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3158 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3160 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3161 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3162 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3163 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3164 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3165 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3166 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3167 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3168 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3169 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3170 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3171 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3172 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3173 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3174 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3175 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3176 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3177 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3178 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3179 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3180 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3181 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3182 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3183 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3203 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3205 void VM_CL_Cmd_Init(void)
3207 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3208 if(vm_polygons_initialized)
3210 Mem_FreePool(&vm_polygons_pool);
3211 vm_polygons_initialized = false;
3215 void VM_CL_Cmd_Reset(void)
3217 if(vm_polygons_initialized)
3219 Mem_FreePool(&vm_polygons_pool);
3220 vm_polygons_initialized = false;