5 #include "cl_collision.h"
8 //============================================================================
10 //[515]: unsolved PROBLEMS
11 //- finish player physics code (cs_runplayerphysics)
13 //- RF_DEPTHHACK is not like it should be
14 //- add builtin that sets cl.viewangles instead of reading "input_angles" global
15 //- finish lines support for R_Polygon***
16 //- insert selecttraceline into traceline somehow
18 //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)
19 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
21 sfx_t *S_FindName(const char *name);
22 int Sbar_GetPlayer (int index);
23 void Sbar_SortFrags (void);
24 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
25 void CSQC_RelinkAllEntities (int drawmask);
26 void CSQC_RelinkCSQCEntities (void);
27 const char *Key_GetBind (int key);
34 // #1 void(vector ang) makevectors
35 static void VM_CL_makevectors (void)
37 VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
38 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up);
41 // #2 void(entity e, vector o) setorigin
42 static void VM_CL_setorigin (void)
46 VM_SAFEPARMCOUNT(2, VM_CL_setorigin);
48 e = PRVM_G_EDICT(OFS_PARM0);
49 if (e == prog->edicts)
51 VM_Warning("setorigin: can not modify world entity\n");
54 if (e->priv.required->free)
56 VM_Warning("setorigin: can not modify free entity\n");
59 org = PRVM_G_VECTOR(OFS_PARM1);
60 VectorCopy (org, e->fields.client->origin);
64 // #3 void(entity e, string m) setmodel
65 static void VM_CL_setmodel (void)
72 VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
74 e = PRVM_G_EDICT(OFS_PARM0);
75 m = PRVM_G_STRING(OFS_PARM1);
76 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
78 if (!strcmp(cl.csqc_model_precache[i]->name, m))
80 e->fields.client->model = PRVM_SetEngineString(cl.csqc_model_precache[i]->name);
81 e->fields.client->modelindex = -(i+1);
86 for (i = 0;i < MAX_MODELS;i++)
88 mod = cl.model_precache[i];
89 if (mod && !strcmp(mod->name, m))
91 e->fields.client->model = PRVM_SetEngineString(mod->name);
92 e->fields.client->modelindex = i;
97 e->fields.client->modelindex = 0;
98 e->fields.client->model = 0;
101 // #4 void(entity e, vector min, vector max) setsize
102 static void VM_CL_setsize (void)
106 VM_SAFEPARMCOUNT(3, VM_CL_setsize);
108 e = PRVM_G_EDICT(OFS_PARM0);
109 if (e == prog->edicts)
111 VM_Warning("setsize: can not modify world entity\n");
114 if (e->priv.server->free)
116 VM_Warning("setsize: can not modify free entity\n");
119 min = PRVM_G_VECTOR(OFS_PARM1);
120 max = PRVM_G_VECTOR(OFS_PARM2);
122 VectorCopy (min, e->fields.client->mins);
123 VectorCopy (max, e->fields.client->maxs);
124 VectorSubtract (max, min, e->fields.client->size);
129 // #8 void(entity e, float chan, string samp, float volume, float atten) sound
130 static void VM_CL_sound (void)
134 prvm_edict_t *entity;
138 VM_SAFEPARMCOUNT(5, VM_CL_sound);
140 entity = PRVM_G_EDICT(OFS_PARM0);
141 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
142 sample = PRVM_G_STRING(OFS_PARM2);
143 volume = PRVM_G_FLOAT(OFS_PARM3);
144 attenuation = PRVM_G_FLOAT(OFS_PARM4);
146 if (volume < 0 || volume > 1)
148 VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
152 if (attenuation < 0 || attenuation > 4)
154 VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
158 if (channel < 0 || channel > 7)
160 VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
164 S_StartSound(32768 + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), entity->fields.client->origin, volume, attenuation);
167 // #483 void(vector origin, string sample, float volume, float attenuation) pointsound
168 static void VM_CL_pointsound(void)
175 VM_SAFEPARMCOUNT(4, VM_CL_pointsound);
177 VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org);
178 sample = PRVM_G_STRING(OFS_PARM1);
179 volume = PRVM_G_FLOAT(OFS_PARM2);
180 attenuation = PRVM_G_FLOAT(OFS_PARM3);
182 if (volume < 0 || volume > 1)
184 VM_Warning("VM_CL_pointsound: volume must be in range 0-1\n");
188 if (attenuation < 0 || attenuation > 4)
190 VM_Warning("VM_CL_pointsound: attenuation must be in range 0-4\n");
194 // Send World Entity as Entity to Play Sound (for CSQC, that is 32768)
195 S_StartSound(32768, 0, S_FindName(sample), org, volume, attenuation);
198 // #14 entity() spawn
199 static void VM_CL_spawn (void)
202 ed = PRVM_ED_Alloc();
203 ed->fields.client->entnum = PRVM_NUM_FOR_EDICT(ed); //[515]: not needed any more ?
207 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
208 static void VM_CL_traceline (void)
215 VM_SAFEPARMCOUNTRANGE(4, 8, VM_CL_traceline); // allow more parameters for future expansion
217 prog->xfunction->builtinsprofile += 30;
219 v1 = PRVM_G_VECTOR(OFS_PARM0);
220 v2 = PRVM_G_VECTOR(OFS_PARM1);
221 move = (int)PRVM_G_FLOAT(OFS_PARM2);
222 ent = PRVM_G_EDICT(OFS_PARM3);
224 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]))
225 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));
227 trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
229 VM_SetTraceGlobals(&trace);
236 Used for use tracing and shot targeting
237 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
238 if the tryents flag is set.
240 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
243 // LordHavoc: added this for my own use, VERY useful, similar to traceline
244 static void VM_CL_tracebox (void)
246 float *v1, *v2, *m1, *m2;
251 VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
253 prog->xfunction->builtinsprofile += 30;
255 v1 = PRVM_G_VECTOR(OFS_PARM0);
256 m1 = PRVM_G_VECTOR(OFS_PARM1);
257 m2 = PRVM_G_VECTOR(OFS_PARM2);
258 v2 = PRVM_G_VECTOR(OFS_PARM3);
259 move = (int)PRVM_G_FLOAT(OFS_PARM4);
260 ent = PRVM_G_EDICT(OFS_PARM5);
262 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]))
263 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));
265 trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
267 VM_SetTraceGlobals(&trace);
270 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
275 vec3_t original_origin;
276 vec3_t original_velocity;
277 vec3_t original_angles;
278 vec3_t original_avelocity;
282 VectorCopy(tossent->fields.client->origin , original_origin );
283 VectorCopy(tossent->fields.client->velocity , original_velocity );
284 VectorCopy(tossent->fields.client->angles , original_angles );
285 VectorCopy(tossent->fields.client->avelocity, original_avelocity);
287 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
288 if (val != NULL && val->_float != 0)
289 gravity = val->_float;
292 gravity *= cl.movevars_gravity * 0.05;
294 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
296 tossent->fields.client->velocity[2] -= gravity;
297 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
298 VectorScale (tossent->fields.client->velocity, 0.05, move);
299 VectorAdd (tossent->fields.client->origin, move, end);
300 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);
301 VectorCopy (trace.endpos, tossent->fields.client->origin);
303 if (trace.fraction < 1)
307 VectorCopy(original_origin , tossent->fields.client->origin );
308 VectorCopy(original_velocity , tossent->fields.client->velocity );
309 VectorCopy(original_angles , tossent->fields.client->angles );
310 VectorCopy(original_avelocity, tossent->fields.client->avelocity);
315 static void VM_CL_tracetoss (void)
319 prvm_edict_t *ignore;
321 prog->xfunction->builtinsprofile += 600;
323 VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
325 ent = PRVM_G_EDICT(OFS_PARM0);
326 if (ent == prog->edicts)
328 VM_Warning("tracetoss: can not use world entity\n");
331 ignore = PRVM_G_EDICT(OFS_PARM1);
333 trace = CL_Trace_Toss (ent, ignore);
335 VM_SetTraceGlobals(&trace);
339 // #20 void(string s) precache_model
340 static void VM_CL_precache_model (void)
346 VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
348 name = PRVM_G_STRING(OFS_PARM0);
349 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
351 if(!strcmp(cl.csqc_model_precache[i]->name, name))
353 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
357 PRVM_G_FLOAT(OFS_RETURN) = 0;
358 m = Mod_ForName(name, false, false, false);
361 for (i = 0;i < MAX_MODELS;i++)
363 if (!cl.csqc_model_precache[i])
365 cl.csqc_model_precache[i] = (model_t*)m;
366 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
370 VM_Warning("VM_CL_precache_model: no free models\n");
373 VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
376 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
381 ent = PRVM_NEXT_EDICT(prog->edicts);
382 for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
384 if (ent->priv.required->free)
386 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
392 // #22 entity(vector org, float rad) findradius
393 static void VM_CL_findradius (void)
395 prvm_edict_t *ent, *chain;
396 vec_t radius, radius2;
397 vec3_t org, eorg, mins, maxs;
398 int i, numtouchedicts;
399 prvm_edict_t *touchedicts[MAX_EDICTS];
401 VM_SAFEPARMCOUNT(2, VM_CL_findradius);
403 chain = (prvm_edict_t *)prog->edicts;
405 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
406 radius = PRVM_G_FLOAT(OFS_PARM1);
407 radius2 = radius * radius;
409 mins[0] = org[0] - (radius + 1);
410 mins[1] = org[1] - (radius + 1);
411 mins[2] = org[2] - (radius + 1);
412 maxs[0] = org[0] + (radius + 1);
413 maxs[1] = org[1] + (radius + 1);
414 maxs[2] = org[2] + (radius + 1);
415 numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
416 if (numtouchedicts > MAX_EDICTS)
418 // this never happens //[515]: for what then ?
419 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
420 numtouchedicts = MAX_EDICTS;
422 for (i = 0;i < numtouchedicts;i++)
424 ent = touchedicts[i];
425 // Quake did not return non-solid entities but darkplaces does
426 // (note: this is the reason you can't blow up fallen zombies)
427 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
429 // LordHavoc: compare against bounding box rather than center so it
430 // doesn't miss large objects, and use DotProduct instead of Length
431 // for a major speedup
432 VectorSubtract(org, ent->fields.client->origin, eorg);
433 if (sv_gameplayfix_findradiusdistancetobox.integer)
435 eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
436 eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
437 eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
440 VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
441 if (DotProduct(eorg, eorg) < radius2)
443 ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
448 VM_RETURN_EDICT(chain);
451 // #34 float() droptofloor
452 static void VM_CL_droptofloor (void)
459 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
461 // assume failure if it returns early
462 PRVM_G_FLOAT(OFS_RETURN) = 0;
464 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
465 if (ent == prog->edicts)
467 VM_Warning("droptofloor: can not modify world entity\n");
470 if (ent->priv.server->free)
472 VM_Warning("droptofloor: can not modify free entity\n");
476 VectorCopy (ent->fields.client->origin, end);
479 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);
481 if (trace.fraction != 1)
483 VectorCopy (trace.endpos, ent->fields.client->origin);
484 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
485 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
486 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
487 PRVM_G_FLOAT(OFS_RETURN) = 1;
488 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
489 // ent->priv.server->suspendedinairflag = true;
493 // #35 void(float style, string value) lightstyle
494 static void VM_CL_lightstyle (void)
499 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
501 i = (int)PRVM_G_FLOAT(OFS_PARM0);
502 c = PRVM_G_STRING(OFS_PARM1);
503 if (i >= cl.max_lightstyle)
505 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
508 strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
509 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
510 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
513 // #40 float(entity e) checkbottom
514 static void VM_CL_checkbottom (void)
516 static int cs_yes, cs_no;
518 vec3_t mins, maxs, start, stop;
523 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
524 ent = PRVM_G_EDICT(OFS_PARM0);
525 PRVM_G_FLOAT(OFS_RETURN) = 0;
527 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
528 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
530 // if all of the points under the corners are solid world, don't bother
531 // with the tougher checks
532 // the corners must be within 16 of the midpoint
533 start[2] = mins[2] - 1;
534 for (x=0 ; x<=1 ; x++)
535 for (y=0 ; y<=1 ; y++)
537 start[0] = x ? maxs[0] : mins[0];
538 start[1] = y ? maxs[1] : mins[1];
539 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
544 PRVM_G_FLOAT(OFS_RETURN) = true;
545 return; // we got out easy
550 // check it for real...
554 // the midpoint must be within 16 of the bottom
555 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
556 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
557 stop[2] = start[2] - 2*sv_stepheight.value;
558 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
560 if (trace.fraction == 1.0)
563 mid = bottom = trace.endpos[2];
565 // the corners must be within 16 of the midpoint
566 for (x=0 ; x<=1 ; x++)
567 for (y=0 ; y<=1 ; y++)
569 start[0] = stop[0] = x ? maxs[0] : mins[0];
570 start[1] = stop[1] = y ? maxs[1] : mins[1];
572 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
574 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
575 bottom = trace.endpos[2];
576 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
581 PRVM_G_FLOAT(OFS_RETURN) = true;
584 // #41 float(vector v) pointcontents
585 static void VM_CL_pointcontents (void)
587 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
588 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
591 // #48 void(vector o, vector d, float color, float count) particle
592 static void VM_CL_particle (void)
597 VM_SAFEPARMCOUNT(4, VM_CL_particle);
599 org = PRVM_G_VECTOR(OFS_PARM0);
600 dir = PRVM_G_VECTOR(OFS_PARM1);
601 color = (int)PRVM_G_FLOAT(OFS_PARM2);
602 count = (int)PRVM_G_FLOAT(OFS_PARM3);
603 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
606 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
607 static void VM_CL_ambientsound (void)
611 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
612 s = S_FindName(PRVM_G_STRING(OFS_PARM0));
613 f = PRVM_G_VECTOR(OFS_PARM1);
614 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
617 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
618 static void VM_CL_getlight (void)
620 vec3_t ambientcolor, diffusecolor, diffusenormal;
623 VM_SAFEPARMCOUNT(1, VM_CL_getlight);
625 p = PRVM_G_VECTOR(OFS_PARM0);
626 VectorClear(ambientcolor);
627 VectorClear(diffusecolor);
628 VectorClear(diffusenormal);
629 if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
630 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
631 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
635 //============================================================================
636 //[515]: SCENE MANAGER builtins
637 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
639 static void CSQC_R_RecalcView (void)
641 extern matrix4x4_t viewmodelmatrix;
642 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);
643 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);
646 void CL_RelinkLightFlashes(void);
647 //#300 void() clearscene (EXT_CSQC)
648 static void VM_CL_R_ClearScene (void)
650 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
651 // clear renderable entity and light lists
652 r_refdef.numentities = 0;
653 r_refdef.numlights = 0;
654 // FIXME: restore these to the values from VM_CL_UpdateView
658 r_view.width = vid.width;
659 r_view.height = vid.height;
661 // FIXME: restore frustum_x/frustum_y
662 r_view.useperspective = true;
663 r_view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
664 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
665 r_view.frustum_x *= r_refdef.frustumscale_x;
666 r_view.frustum_y *= r_refdef.frustumscale_y;
667 r_view.ortho_x = scr_fov.value * (3.0 / 4.0) * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
668 r_view.ortho_y = scr_fov.value * (3.0 / 4.0);
669 // FIXME: restore cl.csqc_origin
670 // FIXME: restore cl.csqc_angles
671 cl.csqc_vidvars.drawworld = true;
672 cl.csqc_vidvars.drawenginesbar = false;
673 cl.csqc_vidvars.drawcrosshair = false;
676 //#301 void(float mask) addentities (EXT_CSQC)
677 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
678 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
679 static void VM_CL_R_AddEntities (void)
683 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
684 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
685 CSQC_RelinkAllEntities(drawmask);
686 CL_RelinkLightFlashes();
688 prog->globals.client->time = cl.time;
689 for(i=1;i<prog->num_edicts;i++)
691 ed = &prog->edicts[i];
692 if(ed->priv.required->free)
695 if(ed->priv.required->free)
697 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
699 if(ed->priv.required->free)
701 if(!((int)ed->fields.client->drawmask & drawmask))
703 CSQC_AddRenderEdict(ed);
707 //#302 void(entity ent) addentity (EXT_CSQC)
708 static void VM_CL_R_AddEntity (void)
710 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
711 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
714 //#303 float(float property, ...) setproperty (EXT_CSQC)
715 static void VM_CL_R_SetView (void)
721 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
723 c = (int)PRVM_G_FLOAT(OFS_PARM0);
724 f = PRVM_G_VECTOR(OFS_PARM1);
725 k = PRVM_G_FLOAT(OFS_PARM1);
729 case VF_MIN: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
730 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
732 case VF_MIN_X: r_view.x = (int)(k * vid.width / vid_conwidth.value);
734 case VF_MIN_Y: r_view.y = (int)(k * vid.height / vid_conheight.value);
736 case VF_SIZE: r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
737 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
739 case VF_SIZE_Y: r_view.width = (int)(k * vid.width / vid_conwidth.value);
741 case VF_SIZE_X: r_view.height = (int)(k * vid.height / vid_conheight.value);
743 case VF_VIEWPORT: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
744 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
745 f = PRVM_G_VECTOR(OFS_PARM2);
746 r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
747 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
749 case VF_FOV: r_view.frustum_x = tan(f[0] * M_PI / 360.0);r_view.ortho_x = f[0];
750 r_view.frustum_y = tan(f[1] * M_PI / 360.0);r_view.ortho_y = f[1];
752 case VF_FOVX: r_view.frustum_x = tan(k * M_PI / 360.0);r_view.ortho_x = k;
754 case VF_FOVY: r_view.frustum_y = tan(k * M_PI / 360.0);r_view.ortho_y = k;
756 case VF_ORIGIN: VectorCopy(f, cl.csqc_origin);
759 case VF_ORIGIN_X: cl.csqc_origin[0] = k;
762 case VF_ORIGIN_Y: cl.csqc_origin[1] = k;
765 case VF_ORIGIN_Z: cl.csqc_origin[2] = k;
768 case VF_ANGLES: VectorCopy(f, cl.csqc_angles);
771 case VF_ANGLES_X: cl.csqc_angles[0] = k;
774 case VF_ANGLES_Y: cl.csqc_angles[1] = k;
777 case VF_ANGLES_Z: cl.csqc_angles[2] = k;
780 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
782 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
784 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
787 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
789 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
791 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
793 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
796 case VF_PERSPECTIVE: r_view.useperspective = k != 0;
799 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
800 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
803 PRVM_G_FLOAT(OFS_RETURN) = 1;
806 //#304 void() renderscene (EXT_CSQC)
807 static void VM_CL_R_RenderScene (void)
809 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
810 // we need to update any RENDER_VIEWMODEL entities at this point because
811 // csqc supplies its own view matrix
812 CL_UpdateViewEntities();
817 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
818 static void VM_CL_R_AddDynamicLight (void)
822 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
824 // if we've run out of dlights, just return
825 if (r_refdef.numlights >= MAX_DLIGHTS)
828 pos = PRVM_G_VECTOR(OFS_PARM0);
829 col = PRVM_G_VECTOR(OFS_PARM2);
830 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
831 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);
834 //============================================================================
836 //#310 vector (vector v) cs_unproject (EXT_CSQC)
837 static void VM_CL_unproject (void)
842 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
843 f = PRVM_G_VECTOR(OFS_PARM0);
844 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);
845 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
848 //#311 vector (vector v) cs_project (EXT_CSQC)
849 static void VM_CL_project (void)
855 VM_SAFEPARMCOUNT(1, VM_CL_project);
856 f = PRVM_G_VECTOR(OFS_PARM0);
857 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
858 Matrix4x4_Transform(&m, f, v);
859 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]);
862 //#330 float(float stnum) getstatf (EXT_CSQC)
863 static void VM_CL_getstatf (void)
871 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
872 i = (int)PRVM_G_FLOAT(OFS_PARM0);
873 if(i < 0 || i >= MAX_CL_STATS)
875 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
879 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
882 //#331 float(float stnum) getstati (EXT_CSQC)
883 static void VM_CL_getstati (void)
886 int firstbit, bitcount;
888 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
890 index = (int)PRVM_G_FLOAT(OFS_PARM0);
893 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
895 bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
905 if(index < 0 || index >= MAX_CL_STATS)
907 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
911 if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from.
912 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
913 PRVM_G_FLOAT(OFS_RETURN) = i;
916 //#332 string(float firststnum) getstats (EXT_CSQC)
917 static void VM_CL_getstats (void)
921 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
922 i = (int)PRVM_G_FLOAT(OFS_PARM0);
923 if(i < 0 || i > MAX_CL_STATS-4)
925 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
926 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
929 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
930 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
933 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
934 static void VM_CL_setmodelindex (void)
938 struct model_s *model;
940 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
942 t = PRVM_G_EDICT(OFS_PARM0);
944 i = (int)PRVM_G_FLOAT(OFS_PARM1);
946 t->fields.client->model = 0;
947 t->fields.client->modelindex = 0;
952 model = CL_GetModelByIndex(i);
955 VM_Warning("VM_CL_setmodelindex: null model\n");
958 t->fields.client->model = PRVM_SetEngineString(model->name);
959 t->fields.client->modelindex = i;
962 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
963 static void VM_CL_modelnameforindex (void)
967 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
969 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
970 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
971 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
974 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
975 static void VM_CL_particleeffectnum (void)
978 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
979 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
982 PRVM_G_FLOAT(OFS_RETURN) = i;
985 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
986 static void VM_CL_trailparticles (void)
991 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
993 t = PRVM_G_EDICT(OFS_PARM0);
994 i = (int)PRVM_G_FLOAT(OFS_PARM1);
995 start = PRVM_G_VECTOR(OFS_PARM2);
996 end = PRVM_G_VECTOR(OFS_PARM3);
998 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);
1001 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
1002 static void VM_CL_pointparticles (void)
1006 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
1007 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1008 f = PRVM_G_VECTOR(OFS_PARM1);
1009 v = PRVM_G_VECTOR(OFS_PARM2);
1010 n = (int)PRVM_G_FLOAT(OFS_PARM3);
1011 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1014 //#342 string(float keynum) getkeybind (EXT_CSQC)
1015 static void VM_CL_getkeybind (void)
1017 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
1018 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
1021 //#343 void(float usecursor) setcursormode (EXT_CSQC)
1022 static void VM_CL_setcursormode (void)
1024 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
1025 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
1026 cl_ignoremousemove = true;
1029 //#345 float(float framenum) getinputstate (EXT_CSQC)
1030 static void VM_CL_getinputstate (void)
1033 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1034 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1035 for (i = 0;i < cl.movement_numqueue;i++)
1036 if (cl.movement_queue[i].sequence == frame)
1038 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
1039 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
1040 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
1041 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
1042 if(cl.movement_queue[i].crouch)
1044 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1045 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1049 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1050 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1055 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1056 static void VM_CL_setsensitivityscale (void)
1058 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1059 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1062 //#347 void() runstandardplayerphysics (EXT_CSQC)
1063 static void VM_CL_runplayerphysics (void)
1067 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1068 static void VM_CL_getplayerkey (void)
1074 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1076 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1077 c = PRVM_G_STRING(OFS_PARM1);
1078 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1081 i = Sbar_GetPlayer(i);
1087 if(!strcasecmp(c, "name"))
1088 strlcpy(t, cl.scores[i].name, sizeof(t));
1090 if(!strcasecmp(c, "frags"))
1091 sprintf(t, "%i", cl.scores[i].frags);
1093 if(!strcasecmp(c, "ping"))
1094 sprintf(t, "%i", cl.scores[i].qw_ping);
1096 if(!strcasecmp(c, "pl"))
1097 sprintf(t, "%i", cl.scores[i].qw_packetloss);
1099 if(!strcasecmp(c, "entertime"))
1100 sprintf(t, "%f", cl.scores[i].qw_entertime);
1102 if(!strcasecmp(c, "colors"))
1103 sprintf(t, "%i", cl.scores[i].colors);
1105 if(!strcasecmp(c, "topcolor"))
1106 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1108 if(!strcasecmp(c, "bottomcolor"))
1109 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1111 if(!strcasecmp(c, "viewentity"))
1112 sprintf(t, "%i", i+1);
1115 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1118 //#349 float() isdemo (EXT_CSQC)
1119 static void VM_CL_isdemo (void)
1121 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1122 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1125 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1126 static void VM_CL_setlistener (void)
1128 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1129 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));
1130 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1133 //#352 void(string cmdname) registercommand (EXT_CSQC)
1134 static void VM_CL_registercmd (void)
1137 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1138 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1142 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1143 t = (char *)Z_Malloc(alloclen);
1144 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1145 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1148 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1152 //#360 float() readbyte (EXT_CSQC)
1153 static void VM_CL_ReadByte (void)
1155 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1156 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1159 //#361 float() readchar (EXT_CSQC)
1160 static void VM_CL_ReadChar (void)
1162 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1163 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1166 //#362 float() readshort (EXT_CSQC)
1167 static void VM_CL_ReadShort (void)
1169 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1170 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1173 //#363 float() readlong (EXT_CSQC)
1174 static void VM_CL_ReadLong (void)
1176 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1177 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1180 //#364 float() readcoord (EXT_CSQC)
1181 static void VM_CL_ReadCoord (void)
1183 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1184 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1187 //#365 float() readangle (EXT_CSQC)
1188 static void VM_CL_ReadAngle (void)
1190 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1191 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1194 //#366 string() readstring (EXT_CSQC)
1195 static void VM_CL_ReadString (void)
1197 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1198 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1201 //#367 float() readfloat (EXT_CSQC)
1202 static void VM_CL_ReadFloat (void)
1204 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1205 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1208 //////////////////////////////////////////////////////////
1210 static void VM_CL_makestatic (void)
1214 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1216 ent = PRVM_G_EDICT(OFS_PARM0);
1217 if (ent == prog->edicts)
1219 VM_Warning("makestatic: can not modify world entity\n");
1222 if (ent->priv.server->free)
1224 VM_Warning("makestatic: can not modify free entity\n");
1228 if (cl.num_static_entities < cl.max_static_entities)
1232 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1234 // copy it to the current state
1235 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1236 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1237 staticent->render.framelerp = 0;
1238 // make torchs play out of sync
1239 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1240 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1241 staticent->render.skinnum = (int)ent->fields.client->skin;
1242 staticent->render.effects = (int)ent->fields.client->effects;
1243 staticent->render.alpha = 1;
1244 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1245 staticent->render.scale = 1;
1246 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1247 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1250 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1251 if (renderflags & RF_USEAXIS)
1254 VectorNegate(prog->globals.client->v_right, left);
1255 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1256 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1259 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);
1260 CL_UpdateRenderEntity(&staticent->render);
1262 // either fullbright or lit
1263 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1264 staticent->render.flags |= RENDER_LIGHT;
1265 // turn off shadows from transparent objects
1266 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1267 staticent->render.flags |= RENDER_SHADOW;
1270 Con_Printf("Too many static entities");
1272 // throw the entity away now
1276 //=================================================================//
1282 copies data from one entity to another
1284 copyentity(src, dst)
1287 static void VM_CL_copyentity (void)
1289 prvm_edict_t *in, *out;
1290 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1291 in = PRVM_G_EDICT(OFS_PARM0);
1292 if (in == prog->edicts)
1294 VM_Warning("copyentity: can not read world entity\n");
1297 if (in->priv.server->free)
1299 VM_Warning("copyentity: can not read free entity\n");
1302 out = PRVM_G_EDICT(OFS_PARM1);
1303 if (out == prog->edicts)
1305 VM_Warning("copyentity: can not modify world entity\n");
1308 if (out->priv.server->free)
1310 VM_Warning("copyentity: can not modify free entity\n");
1313 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1317 //=================================================================//
1319 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1320 static void VM_CL_effect (void)
1322 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1323 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));
1326 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1327 static void VM_CL_te_blood (void)
1331 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1332 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1334 pos = PRVM_G_VECTOR(OFS_PARM0);
1335 CL_FindNonSolidLocation(pos, pos2, 4);
1336 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1339 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1340 static void VM_CL_te_bloodshower (void)
1344 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1345 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1347 speed = PRVM_G_FLOAT(OFS_PARM2);
1354 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1357 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1358 static void VM_CL_te_explosionrgb (void)
1362 matrix4x4_t tempmatrix;
1363 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1364 pos = PRVM_G_VECTOR(OFS_PARM0);
1365 CL_FindNonSolidLocation(pos, pos2, 10);
1366 CL_ParticleExplosion(pos2);
1367 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1368 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);
1371 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1372 static void VM_CL_te_particlecube (void)
1374 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1375 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));
1378 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1379 static void VM_CL_te_particlerain (void)
1381 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1382 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);
1385 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1386 static void VM_CL_te_particlesnow (void)
1388 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1389 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);
1392 // #411 void(vector org, vector vel, float howmany) te_spark
1393 static void VM_CL_te_spark (void)
1397 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1399 pos = PRVM_G_VECTOR(OFS_PARM0);
1400 CL_FindNonSolidLocation(pos, pos2, 4);
1401 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1404 extern cvar_t cl_sound_ric_gunshot;
1405 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1406 static void VM_CL_te_gunshotquad (void)
1411 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1413 pos = PRVM_G_VECTOR(OFS_PARM0);
1414 CL_FindNonSolidLocation(pos, pos2, 4);
1415 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1416 if(cl_sound_ric_gunshot.integer >= 2)
1418 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1422 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1423 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1424 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1429 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1430 static void VM_CL_te_spikequad (void)
1435 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1437 pos = PRVM_G_VECTOR(OFS_PARM0);
1438 CL_FindNonSolidLocation(pos, pos2, 4);
1439 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1440 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1444 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1445 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1446 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1450 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1451 static void VM_CL_te_superspikequad (void)
1456 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1458 pos = PRVM_G_VECTOR(OFS_PARM0);
1459 CL_FindNonSolidLocation(pos, pos2, 4);
1460 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1461 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1465 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1466 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1467 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1471 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1472 static void VM_CL_te_explosionquad (void)
1476 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1478 pos = PRVM_G_VECTOR(OFS_PARM0);
1479 CL_FindNonSolidLocation(pos, pos2, 10);
1480 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1481 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1484 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1485 static void VM_CL_te_smallflash (void)
1489 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1491 pos = PRVM_G_VECTOR(OFS_PARM0);
1492 CL_FindNonSolidLocation(pos, pos2, 10);
1493 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1496 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1497 static void VM_CL_te_customflash (void)
1501 matrix4x4_t tempmatrix;
1502 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1504 pos = PRVM_G_VECTOR(OFS_PARM0);
1505 CL_FindNonSolidLocation(pos, pos2, 4);
1506 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1507 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);
1510 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1511 static void VM_CL_te_gunshot (void)
1516 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1518 pos = PRVM_G_VECTOR(OFS_PARM0);
1519 CL_FindNonSolidLocation(pos, pos2, 4);
1520 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1521 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1523 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1527 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1528 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1529 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1534 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1535 static void VM_CL_te_spike (void)
1540 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1542 pos = PRVM_G_VECTOR(OFS_PARM0);
1543 CL_FindNonSolidLocation(pos, pos2, 4);
1544 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1545 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1549 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1550 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1551 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1555 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1556 static void VM_CL_te_superspike (void)
1561 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1563 pos = PRVM_G_VECTOR(OFS_PARM0);
1564 CL_FindNonSolidLocation(pos, pos2, 4);
1565 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1566 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1570 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1571 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1572 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1576 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1577 static void VM_CL_te_explosion (void)
1581 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1583 pos = PRVM_G_VECTOR(OFS_PARM0);
1584 CL_FindNonSolidLocation(pos, pos2, 10);
1585 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1586 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1589 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1590 static void VM_CL_te_tarexplosion (void)
1594 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1596 pos = PRVM_G_VECTOR(OFS_PARM0);
1597 CL_FindNonSolidLocation(pos, pos2, 10);
1598 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1599 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1602 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1603 static void VM_CL_te_wizspike (void)
1607 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1609 pos = PRVM_G_VECTOR(OFS_PARM0);
1610 CL_FindNonSolidLocation(pos, pos2, 4);
1611 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1612 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1615 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1616 static void VM_CL_te_knightspike (void)
1620 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1622 pos = PRVM_G_VECTOR(OFS_PARM0);
1623 CL_FindNonSolidLocation(pos, pos2, 4);
1624 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1625 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1628 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1629 static void VM_CL_te_lavasplash (void)
1631 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1632 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1635 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1636 static void VM_CL_te_teleport (void)
1638 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1639 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1642 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1643 static void VM_CL_te_explosion2 (void)
1647 matrix4x4_t tempmatrix;
1648 int colorStart, colorLength;
1649 unsigned char *tempcolor;
1650 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1652 pos = PRVM_G_VECTOR(OFS_PARM0);
1653 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1654 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1655 CL_FindNonSolidLocation(pos, pos2, 10);
1656 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1657 tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
1658 color[0] = tempcolor[0] * (2.0f / 255.0f);
1659 color[1] = tempcolor[1] * (2.0f / 255.0f);
1660 color[2] = tempcolor[2] * (2.0f / 255.0f);
1661 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1662 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);
1663 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1667 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1668 static void VM_CL_te_lightning1 (void)
1670 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1671 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1674 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1675 static void VM_CL_te_lightning2 (void)
1677 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1678 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1681 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1682 static void VM_CL_te_lightning3 (void)
1684 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1685 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1688 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1689 static void VM_CL_te_beam (void)
1691 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1692 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1695 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1696 static void VM_CL_te_plasmaburn (void)
1700 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1702 pos = PRVM_G_VECTOR(OFS_PARM0);
1703 CL_FindNonSolidLocation(pos, pos2, 4);
1704 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1707 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1708 static void VM_CL_te_flamejet (void)
1712 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1713 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1715 pos = PRVM_G_VECTOR(OFS_PARM0);
1716 CL_FindNonSolidLocation(pos, pos2, 4);
1717 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1721 //====================================================================
1724 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1726 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1728 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1730 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1733 // #434 float(entity e, float s) getsurfacenumpoints
1734 static void VM_CL_getsurfacenumpoints(void)
1737 msurface_t *surface;
1738 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1739 // return 0 if no such surface
1740 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1742 PRVM_G_FLOAT(OFS_RETURN) = 0;
1746 // note: this (incorrectly) assumes it is a simple polygon
1747 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1750 // #435 vector(entity e, float s, float n) getsurfacepoint
1751 static void VM_CL_getsurfacepoint(void)
1755 msurface_t *surface;
1757 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1758 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1759 ed = PRVM_G_EDICT(OFS_PARM0);
1760 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1762 // note: this (incorrectly) assumes it is a simple polygon
1763 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1764 if (pointnum < 0 || pointnum >= surface->num_vertices)
1766 // FIXME: implement rotation/scaling
1767 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1769 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
1770 // float SPA_POSITION = 0;
1771 // float SPA_S_AXIS = 1;
1772 // float SPA_R_AXIS = 2;
1773 // float SPA_T_AXIS = 3; // same as SPA_NORMAL
1774 // float SPA_TEXCOORDS0 = 4;
1775 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1776 // float SPA_LIGHTMAP0_COLOR = 6;
1777 // TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black]
1778 static void VM_CL_getsurfacepointattribute(void)
1782 msurface_t *surface;
1786 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1787 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1788 ed = PRVM_G_EDICT(OFS_PARM0);
1789 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1791 // note: this (incorrectly) assumes it is a simple polygon
1792 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1793 if (pointnum < 0 || pointnum >= surface->num_vertices)
1796 // FIXME: implement rotation/scaling
1797 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
1799 switch( attributetype ) {
1800 // float SPA_POSITION = 0;
1802 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1804 // float SPA_S_AXIS = 1;
1806 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1808 // float SPA_R_AXIS = 2;
1810 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1812 // float SPA_T_AXIS = 3; // same as SPA_NORMAL
1814 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1816 // float SPA_TEXCOORDS0 = 4;
1818 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1819 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
1820 ret[0] = texcoord[0];
1821 ret[1] = texcoord[1];
1825 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1827 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1828 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
1829 ret[0] = texcoord[0];
1830 ret[1] = texcoord[1];
1834 // float SPA_LIGHTMAP0_COLOR = 6;
1836 // ignore alpha for now..
1837 VectorCopy( &(model->surfmesh.data_normal3f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
1840 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
1844 // #436 vector(entity e, float s) getsurfacenormal
1845 static void VM_CL_getsurfacenormal(void)
1848 msurface_t *surface;
1850 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1851 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1852 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1854 // FIXME: implement rotation/scaling
1855 // note: this (incorrectly) assumes it is a simple polygon
1856 // note: this only returns the first triangle, so it doesn't work very
1857 // well for curved surfaces or arbitrary meshes
1858 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);
1859 VectorNormalize(normal);
1860 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1863 // #437 string(entity e, float s) getsurfacetexture
1864 static void VM_CL_getsurfacetexture(void)
1867 msurface_t *surface;
1868 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1869 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1870 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1872 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1875 // #438 float(entity e, vector p) getsurfacenearpoint
1876 static void VM_CL_getsurfacenearpoint(void)
1878 int surfacenum, best;
1880 vec_t dist, bestdist;
1882 model_t *model = NULL;
1883 msurface_t *surface;
1885 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1886 PRVM_G_FLOAT(OFS_RETURN) = -1;
1887 ed = PRVM_G_EDICT(OFS_PARM0);
1888 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1891 // FIXME: implement rotation/scaling
1892 point = PRVM_G_VECTOR(OFS_PARM1);
1893 VectorSubtract(point, ed->fields.client->origin, p);
1895 bestdist = 1000000000;
1896 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1898 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1899 // first see if the nearest point on the surface's box is closer than the previous match
1900 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1901 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1902 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1903 dist = VectorLength2(clipped);
1904 if (dist < bestdist)
1906 // it is, check the nearest point on the actual geometry
1907 clippointtosurface(model, surface, p, clipped);
1908 VectorSubtract(clipped, p, clipped);
1909 dist += VectorLength2(clipped);
1910 if (dist < bestdist)
1912 // that's closer too, store it as the best match
1918 PRVM_G_FLOAT(OFS_RETURN) = best;
1921 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1922 static void VM_CL_getsurfaceclippedpoint(void)
1926 msurface_t *surface;
1928 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1929 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1930 ed = PRVM_G_EDICT(OFS_PARM0);
1931 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1933 // FIXME: implement rotation/scaling
1934 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1935 clippointtosurface(model, surface, p, out);
1936 // FIXME: implement rotation/scaling
1937 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1940 // #443 void(entity e, entity tagentity, string tagname) setattachment
1941 static void VM_CL_setattachment (void)
1944 prvm_edict_t *tagentity;
1945 const char *tagname;
1949 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1951 e = PRVM_G_EDICT(OFS_PARM0);
1952 tagentity = PRVM_G_EDICT(OFS_PARM1);
1953 tagname = PRVM_G_STRING(OFS_PARM2);
1955 if (e == prog->edicts)
1957 VM_Warning("setattachment: can not modify world entity\n");
1960 if (e->priv.server->free)
1962 VM_Warning("setattachment: can not modify free entity\n");
1966 if (tagentity == NULL)
1967 tagentity = prog->edicts;
1969 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1971 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1973 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1976 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1978 modelindex = (int)tagentity->fields.client->modelindex;
1979 model = CL_GetModelByIndex(modelindex);
1982 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1984 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);
1987 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));
1991 /////////////////////////////////////////
1992 // DP_MD3_TAGINFO extension coded by VorteX
1994 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1996 model_t *model = CL_GetModelFromEdict(e);
1998 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
2003 // Warnings/errors code:
2004 // 0 - normal (everything all-right)
2007 // 3 - null or non-precached model
2008 // 4 - no tags with requested index
2009 // 5 - runaway loop at attachment chain
2010 extern cvar_t cl_bob;
2011 extern cvar_t cl_bobcycle;
2012 extern cvar_t cl_bobup;
2013 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2016 int reqframe, attachloop;
2017 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2018 prvm_edict_t *attachent;
2021 *out = identitymatrix; // warnings and errors return identical matrix
2023 if (ent == prog->edicts)
2025 if (ent->priv.server->free)
2028 model = CL_GetModelFromEdict(ent);
2033 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
2034 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
2036 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2038 // get initial tag matrix
2041 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2046 tagmatrix = identitymatrix;
2048 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2049 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2053 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2054 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
2056 model = CL_GetModelFromEdict(attachent);
2058 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
2059 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
2061 attachmatrix = identitymatrix;
2063 // apply transformation by child entity matrix
2064 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2065 if (val->_float == 0)
2067 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);
2068 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2069 Matrix4x4_Copy(&tagmatrix, out);
2071 // finally transformate by matrix of tag on parent entity
2072 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2073 Matrix4x4_Copy(&tagmatrix, out);
2077 if (attachloop > 255) // prevent runaway looping
2080 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
2083 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2084 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2085 if (val->_float == 0)
2087 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2088 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);
2089 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2091 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
2092 {// RENDER_VIEWMODEL magic
2093 Matrix4x4_Copy(&tagmatrix, out);
2095 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2096 if (val->_float == 0)
2099 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);
2100 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2103 // Cl_bob, ported from rendering code
2104 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2107 // LordHavoc: this code is *weird*, but not replacable (I think it
2108 // should be done in QC on the server, but oh well, quake is quake)
2109 // LordHavoc: figured out bobup: the time at which the sin is at 180
2110 // degrees (which allows lengthening or squishing the peak or valley)
2111 cycle = cl.time/cl_bobcycle.value;
2112 cycle -= (int)cycle;
2113 if (cycle < cl_bobup.value)
2114 cycle = sin(M_PI * cycle / cl_bobup.value);
2116 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2117 // bob is proportional to velocity in the xy plane
2118 // (don't count Z, or jumping messes it up)
2119 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;
2120 bob = bob*0.3 + bob*0.7*cycle;
2121 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2128 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2129 static void VM_CL_gettagindex (void)
2132 const char *tag_name;
2133 int modelindex, tag_index;
2135 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2137 ent = PRVM_G_EDICT(OFS_PARM0);
2138 tag_name = PRVM_G_STRING(OFS_PARM1);
2139 if (ent == prog->edicts)
2141 VM_Warning("gettagindex: can't affect world entity\n");
2144 if (ent->priv.server->free)
2146 VM_Warning("gettagindex: can't affect free entity\n");
2150 modelindex = (int)ent->fields.client->modelindex;
2152 modelindex = -(modelindex+1);
2154 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2155 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2158 tag_index = CL_GetTagIndex(ent, tag_name);
2160 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2162 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2165 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2166 static void VM_CL_gettaginfo (void)
2170 matrix4x4_t tag_matrix;
2173 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2175 e = PRVM_G_EDICT(OFS_PARM0);
2176 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2177 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2178 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2183 VM_Warning("gettagindex: can't affect world entity\n");
2186 VM_Warning("gettagindex: can't affect free entity\n");
2189 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2192 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2195 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2200 //============================================================================
2202 //====================
2203 //QC POLYGON functions
2204 //====================
2209 float data[36]; //[515]: enough for polygons
2210 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2213 //static float vm_polygon_linewidth = 1;
2214 static mempool_t *vm_polygons_pool = NULL;
2215 static unsigned char vm_current_vertices = 0;
2216 static qboolean vm_polygons_initialized = false;
2217 static vm_polygon_t *vm_polygons = NULL;
2218 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2219 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2220 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2222 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2223 #define VM_POLYGON_FLLINES 32
2224 #define VM_POLYGON_FL2D 64
2225 #define VM_POLYGON_FL4V 128 //4 vertices
2227 static void VM_InitPolygons (void)
2229 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2230 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2231 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2232 vm_polygons_num = VM_DEFPOLYNUM;
2233 vm_drawpolygons_num = 0;
2234 vm_polygonbegin = false;
2235 vm_polygons_initialized = true;
2238 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2240 int surfacelistindex;
2241 // LordHavoc: FIXME: this is stupid code
2242 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2244 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2245 int flags = p->flags & 0x0f;
2247 if(flags == DRAWFLAG_ADDITIVE)
2248 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2249 else if(flags == DRAWFLAG_MODULATE)
2250 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2251 else if(flags == DRAWFLAG_2XMODULATE)
2252 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2254 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2256 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2259 //[515]: is speed is max ?
2260 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2262 qglLineWidth(p->data[13]);CHECKGLERROR
2263 qglBegin(GL_LINE_LOOP);
2264 qglTexCoord1f (p->data[12]);
2265 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2266 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2268 qglTexCoord1f (p->data[14]);
2269 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2270 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2272 if(p->flags & VM_POLYGON_FL3V)
2274 qglTexCoord1f (p->data[16]);
2275 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2276 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2278 if(p->flags & VM_POLYGON_FL4V)
2280 qglTexCoord1f (p->data[18]);
2281 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2282 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2290 qglBegin(GL_POLYGON);
2291 qglTexCoord2f (p->data[12], p->data[13]);
2292 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2293 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2295 qglTexCoord2f (p->data[14], p->data[15]);
2296 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2297 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2299 qglTexCoord2f (p->data[16], p->data[17]);
2300 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2301 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2303 if(p->flags & VM_POLYGON_FL4V)
2305 qglTexCoord2f (p->data[18], p->data[19]);
2306 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2307 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2315 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2317 drawqueuemesh_t mesh;
2318 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2320 mesh.texture = p->tex;
2321 mesh.data_element3i = picelements;
2322 mesh.data_vertex3f = p->data;
2323 mesh.data_texcoord2f = p->data + 12;
2324 mesh.data_color4f = p->data + 20;
2325 if(p->flags & VM_POLYGON_FL4V)
2327 mesh.num_vertices = 4;
2328 mesh.num_triangles = 2;
2332 mesh.num_vertices = 3;
2333 mesh.num_triangles = 1;
2335 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2336 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2338 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2341 void VM_CL_AddPolygonsToMeshQueue (void)
2344 if(!vm_drawpolygons_num)
2346 R_Mesh_Matrix(&identitymatrix);
2347 GL_CullFace(GL_NONE);
2348 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2349 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2350 vm_drawpolygons_num = 0;
2353 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2354 static void VM_CL_R_PolygonBegin (void)
2357 const char *picname;
2358 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2360 if(!vm_polygons_initialized)
2364 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2367 if(vm_drawpolygons_num >= vm_polygons_num)
2369 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2370 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2371 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2372 Mem_Free(vm_polygons);
2374 vm_polygons_num *= 2;
2376 p = &vm_polygons[vm_drawpolygons_num];
2377 picname = PRVM_G_STRING(OFS_PARM0);
2379 p->tex = Draw_CachePic(picname, true)->tex;
2381 p->tex = r_texture_white;
2382 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2383 vm_current_vertices = 0;
2384 vm_polygonbegin = true;
2387 if(PRVM_G_FLOAT(OFS_PARM2))
2388 p->flags |= VM_POLYGON_FL2D;
2389 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2391 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2392 p->flags |= VM_POLYGON_FLLINES;
2397 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2398 static void VM_CL_R_PolygonVertex (void)
2400 float *coords, *tx, *rgb, alpha;
2402 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2404 if(!vm_polygonbegin)
2406 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2409 coords = PRVM_G_VECTOR(OFS_PARM0);
2410 tx = PRVM_G_VECTOR(OFS_PARM1);
2411 rgb = PRVM_G_VECTOR(OFS_PARM2);
2412 alpha = PRVM_G_FLOAT(OFS_PARM3);
2414 p = &vm_polygons[vm_drawpolygons_num];
2415 if(vm_current_vertices > 4)
2417 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2421 p->data[vm_current_vertices*3] = coords[0];
2422 p->data[1+vm_current_vertices*3] = coords[1];
2423 p->data[2+vm_current_vertices*3] = coords[2];
2425 p->data[12+vm_current_vertices*2] = tx[0];
2426 if(!(p->flags & VM_POLYGON_FLLINES))
2427 p->data[13+vm_current_vertices*2] = tx[1];
2429 p->data[20+vm_current_vertices*4] = rgb[0];
2430 p->data[21+vm_current_vertices*4] = rgb[1];
2431 p->data[22+vm_current_vertices*4] = rgb[2];
2432 p->data[23+vm_current_vertices*4] = alpha;
2434 vm_current_vertices++;
2435 if(vm_current_vertices == 4)
2436 p->flags |= VM_POLYGON_FL4V;
2438 if(vm_current_vertices == 3)
2439 p->flags |= VM_POLYGON_FL3V;
2442 //void() R_EndPolygon
2443 static void VM_CL_R_PolygonEnd (void)
2445 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2446 if(!vm_polygonbegin)
2448 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2451 vm_polygonbegin = false;
2452 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2454 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2455 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2457 vm_drawpolygons_num++;
2460 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2463 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2467 if(!vm_polygons_initialized)
2471 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2474 // limit polygons to a vaguely sane amount, beyond this each one just
2475 // replaces the last one
2476 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2477 if(vm_drawpolygons_num >= vm_polygons_num)
2479 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2480 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2481 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2482 Mem_Free(vm_polygons);
2484 vm_polygons_num *= 2;
2486 p = &vm_polygons[vm_drawpolygons_num];
2487 if(picname && picname[0])
2488 p->tex = Draw_CachePic(picname, true)->tex;
2490 p->tex = r_texture_white;
2492 vm_current_vertices = 0;
2493 vm_polygonbegin = true;
2495 p->flags |= VM_POLYGON_FL2D;
2498 p->data[13] = linewidth; //[515]: linewidth
2499 p->flags |= VM_POLYGON_FLLINES;
2503 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2507 if(!vm_polygonbegin)
2509 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2513 p = &vm_polygons[vm_drawpolygons_num];
2514 if(vm_current_vertices > 4)
2516 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2520 p->data[vm_current_vertices*3] = x;
2521 p->data[1+vm_current_vertices*3] = y;
2522 p->data[2+vm_current_vertices*3] = z;
2524 p->data[12+vm_current_vertices*2] = s;
2525 if(!(p->flags & VM_POLYGON_FLLINES))
2526 p->data[13+vm_current_vertices*2] = t;
2528 p->data[20+vm_current_vertices*4] = r;
2529 p->data[21+vm_current_vertices*4] = g;
2530 p->data[22+vm_current_vertices*4] = b;
2531 p->data[23+vm_current_vertices*4] = a;
2533 vm_current_vertices++;
2534 if(vm_current_vertices == 4)
2535 p->flags |= VM_POLYGON_FL4V;
2537 if(vm_current_vertices == 3)
2538 p->flags |= VM_POLYGON_FL3V;
2541 void Debug_PolygonEnd(void)
2543 if(!vm_polygonbegin)
2545 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2548 vm_polygonbegin = false;
2549 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2551 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2552 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2554 vm_drawpolygons_num++;
2557 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2564 Returns false if any part of the bottom of the entity is off an edge that
2569 qboolean CL_CheckBottom (prvm_edict_t *ent)
2571 vec3_t mins, maxs, start, stop;
2576 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2577 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2579 // if all of the points under the corners are solid world, don't bother
2580 // with the tougher checks
2581 // the corners must be within 16 of the midpoint
2582 start[2] = mins[2] - 1;
2583 for (x=0 ; x<=1 ; x++)
2584 for (y=0 ; y<=1 ; y++)
2586 start[0] = x ? maxs[0] : mins[0];
2587 start[1] = y ? maxs[1] : mins[1];
2588 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2592 return true; // we got out easy
2596 // check it for real...
2600 // the midpoint must be within 16 of the bottom
2601 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2602 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2603 stop[2] = start[2] - 2*sv_stepheight.value;
2604 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2606 if (trace.fraction == 1.0)
2608 mid = bottom = trace.endpos[2];
2610 // the corners must be within 16 of the midpoint
2611 for (x=0 ; x<=1 ; x++)
2612 for (y=0 ; y<=1 ; y++)
2614 start[0] = stop[0] = x ? maxs[0] : mins[0];
2615 start[1] = stop[1] = y ? maxs[1] : mins[1];
2617 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2619 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2620 bottom = trace.endpos[2];
2621 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2632 Called by monster program code.
2633 The move will be adjusted for slopes and stairs, but if the move isn't
2634 possible, no move is done and false is returned
2637 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2640 vec3_t oldorg, neworg, end, traceendpos;
2643 prvm_edict_t *enemy;
2647 VectorCopy (ent->fields.client->origin, oldorg);
2648 VectorAdd (ent->fields.client->origin, move, neworg);
2650 // flying monsters don't step up
2651 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2653 // try one move with vertical motion, then one without
2654 for (i=0 ; i<2 ; i++)
2656 VectorAdd (ent->fields.client->origin, move, neworg);
2657 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2658 if (i == 0 && enemy != prog->edicts)
2660 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2666 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);
2668 VM_SetTraceGlobals(&trace);
2670 if (trace.fraction == 1)
2672 VectorCopy(trace.endpos, traceendpos);
2673 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2674 return false; // swim monster left water
2676 VectorCopy (traceendpos, ent->fields.client->origin);
2682 if (enemy == prog->edicts)
2689 // push down from a step height above the wished position
2690 neworg[2] += sv_stepheight.value;
2691 VectorCopy (neworg, end);
2692 end[2] -= sv_stepheight.value*2;
2694 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2696 VM_SetTraceGlobals(&trace);
2698 if (trace.startsolid)
2700 neworg[2] -= sv_stepheight.value;
2701 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2703 VM_SetTraceGlobals(&trace);
2704 if (trace.startsolid)
2707 if (trace.fraction == 1)
2709 // if monster had the ground pulled out, go ahead and fall
2710 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2712 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2715 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2719 return false; // walked off an edge
2722 // check point traces down for dangling corners
2723 VectorCopy (trace.endpos, ent->fields.client->origin);
2725 if (!CL_CheckBottom (ent))
2727 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2728 { // entity had floor mostly pulled out from underneath it
2729 // and is trying to correct
2734 VectorCopy (oldorg, ent->fields.client->origin);
2738 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2739 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2741 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2742 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2754 float(float yaw, float dist[, settrace]) walkmove
2757 static void VM_CL_walkmove (void)
2766 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2768 // assume failure if it returns early
2769 PRVM_G_FLOAT(OFS_RETURN) = 0;
2771 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2772 if (ent == prog->edicts)
2774 VM_Warning("walkmove: can not modify world entity\n");
2777 if (ent->priv.server->free)
2779 VM_Warning("walkmove: can not modify free entity\n");
2782 yaw = PRVM_G_FLOAT(OFS_PARM0);
2783 dist = PRVM_G_FLOAT(OFS_PARM1);
2784 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2786 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2789 yaw = yaw*M_PI*2 / 360;
2791 move[0] = cos(yaw)*dist;
2792 move[1] = sin(yaw)*dist;
2795 // save program state, because CL_movestep may call other progs
2796 oldf = prog->xfunction;
2797 oldself = prog->globals.client->self;
2799 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2802 // restore program state
2803 prog->xfunction = oldf;
2804 prog->globals.client->self = oldself;
2811 string(string key) serverkey
2814 void VM_CL_serverkey(void)
2816 char string[VM_STRINGTEMP_LENGTH];
2817 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2818 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2819 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2822 //============================================================================
2824 prvm_builtin_t vm_cl_builtins[] = {
2825 NULL, // #0 NULL function (not callable) (QUAKE)
2826 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2827 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2828 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2829 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2830 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2831 VM_break, // #6 void() break (QUAKE)
2832 VM_random, // #7 float() random (QUAKE)
2833 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2834 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2835 VM_error, // #10 void(string e) error (QUAKE)
2836 VM_objerror, // #11 void(string e) objerror (QUAKE)
2837 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2838 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2839 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2840 VM_remove, // #15 void(entity e) remove (QUAKE)
2841 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2842 NULL, // #17 entity() checkclient (QUAKE)
2843 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2844 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2845 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2846 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2847 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2848 NULL, // #23 void(string s, ...) bprint (QUAKE)
2849 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2850 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2851 VM_ftos, // #26 string(float f) ftos (QUAKE)
2852 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2853 VM_coredump, // #28 void() coredump (QUAKE)
2854 VM_traceon, // #29 void() traceon (QUAKE)
2855 VM_traceoff, // #30 void() traceoff (QUAKE)
2856 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2857 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2858 NULL, // #33 (QUAKE)
2859 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2860 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2861 VM_rint, // #36 float(float v) rint (QUAKE)
2862 VM_floor, // #37 float(float v) floor (QUAKE)
2863 VM_ceil, // #38 float(float v) ceil (QUAKE)
2864 NULL, // #39 (QUAKE)
2865 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2866 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2867 NULL, // #42 (QUAKE)
2868 VM_fabs, // #43 float(float f) fabs (QUAKE)
2869 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2870 VM_cvar, // #45 float(string s) cvar (QUAKE)
2871 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2872 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2873 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2874 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2875 NULL, // #50 (QUAKE)
2876 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2877 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2878 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2879 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2880 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2881 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2882 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2883 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2884 NULL, // #59 (QUAKE)
2885 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2886 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2887 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2888 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2889 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2890 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2891 NULL, // #66 (QUAKE)
2892 NULL, // #67 void(float step) movetogoal (QUAKE)
2893 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2894 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2895 NULL, // #70 void(string s) changelevel (QUAKE)
2896 NULL, // #71 (QUAKE)
2897 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2898 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2899 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2900 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2901 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2902 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2903 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2904 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2905 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2906 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2907 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2908 NULL, // #83 (QUAKE)
2909 NULL, // #84 (QUAKE)
2910 NULL, // #85 (QUAKE)
2911 NULL, // #86 (QUAKE)
2912 NULL, // #87 (QUAKE)
2913 NULL, // #88 (QUAKE)
2914 NULL, // #89 (QUAKE)
2915 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2916 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2917 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2918 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2919 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2920 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2921 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2922 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2923 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2924 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2925 // FrikaC and Telejano range #100-#199
2936 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2937 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2938 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2939 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2940 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2941 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2942 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2943 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2944 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2945 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3026 // FTEQW range #200-#299
3045 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3048 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3049 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3050 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3051 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3052 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3053 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3054 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3055 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3056 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3057 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3059 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3127 // CSQC range #300-#399
3128 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
3129 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3130 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3131 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3132 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3133 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3134 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3135 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3136 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3138 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3139 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3143 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3144 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3145 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3146 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3147 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3148 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3149 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3150 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3151 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3152 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3153 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3154 VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3155 NULL, // #327 // FIXME add stringwidth() here?
3156 NULL, // #328 // FIXME add drawsubpic() here?
3158 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3159 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3160 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3161 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3162 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3163 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3164 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3165 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3166 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3167 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3168 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3169 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3170 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3171 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3172 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3173 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3174 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3175 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3176 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3177 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3178 VM_isserver, // #350 float() isserver (EXT_CSQC)
3179 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3180 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3181 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3182 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3188 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3189 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3190 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3191 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3192 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3193 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3194 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3195 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3228 // LordHavoc's range #400-#499
3229 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3230 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3231 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3232 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3233 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3234 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3235 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3236 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3237 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)
3238 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3239 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3240 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3241 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3242 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3243 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3244 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3245 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3246 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3247 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3248 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3249 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3250 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3251 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3252 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3253 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3254 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3255 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3256 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3257 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3258 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3259 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3260 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3261 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3262 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3263 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3264 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3265 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3266 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3267 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3268 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3269 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3270 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3271 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3272 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3273 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3274 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3275 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3276 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3277 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3278 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3279 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3280 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3281 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3282 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3283 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3284 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3285 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3286 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3288 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3289 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3290 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3291 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3292 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3293 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3294 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3295 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3296 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3297 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3298 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3299 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3300 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3301 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3302 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3303 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3304 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3305 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3306 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3307 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3308 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3309 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3310 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3311 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3312 VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3313 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3314 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3315 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3316 #ifdef SUPPORT_GECKO
3317 VM_gecko_create, // #487
3318 VM_gecko_destroy, // #488
3319 VM_gecko_navigate, // #489
3320 VM_gecko_keyevent, // #490
3321 VM_gecko_movemouse, // #491
3339 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3341 void VM_CL_Cmd_Init(void)
3343 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3344 if(vm_polygons_initialized)
3346 Mem_FreePool(&vm_polygons_pool);
3347 vm_polygons_initialized = false;
3351 void VM_CL_Cmd_Reset(void)
3353 if(vm_polygons_initialized)
3355 Mem_FreePool(&vm_polygons_pool);
3356 vm_polygons_initialized = false;