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);
29 // #1 void(vector ang) makevectors
30 static void VM_CL_makevectors (void)
32 VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
33 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up);
36 // #2 void(entity e, vector o) setorigin
37 void VM_CL_setorigin (void)
41 VM_SAFEPARMCOUNT(2, VM_CL_setorigin);
43 e = PRVM_G_EDICT(OFS_PARM0);
44 if (e == prog->edicts)
46 VM_Warning("setorigin: can not modify world entity\n");
49 if (e->priv.required->free)
51 VM_Warning("setorigin: can not modify free entity\n");
54 org = PRVM_G_VECTOR(OFS_PARM1);
55 VectorCopy (org, e->fields.client->origin);
59 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max)
65 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
68 VectorCopy (min, e->fields.client->mins);
69 VectorCopy (max, e->fields.client->maxs);
70 VectorSubtract (max, min, e->fields.client->size);
75 // #3 void(entity e, string m) setmodel
76 void VM_CL_setmodel (void)
83 VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
85 e = PRVM_G_EDICT(OFS_PARM0);
86 m = PRVM_G_STRING(OFS_PARM1);
87 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
89 if (!strcmp(cl.csqc_model_precache[i]->name, m))
91 e->fields.client->model = PRVM_SetEngineString(cl.csqc_model_precache[i]->name);
92 e->fields.client->modelindex = -(i+1);
97 for (i = 0;i < MAX_MODELS;i++)
99 mod = cl.model_precache[i];
100 if (mod && !strcmp(mod->name, m))
102 e->fields.client->model = PRVM_SetEngineString(mod->name);
103 e->fields.client->modelindex = i;
108 e->fields.client->modelindex = 0;
109 e->fields.client->model = 0;
110 VM_Warning ("setmodel: model '%s' not precached\n", m);
112 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
115 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs);
118 SetMinMaxSize (e, vec3_origin, vec3_origin);
121 // #4 void(entity e, vector min, vector max) setsize
122 static void VM_CL_setsize (void)
126 VM_SAFEPARMCOUNT(3, VM_CL_setsize);
128 e = PRVM_G_EDICT(OFS_PARM0);
129 if (e == prog->edicts)
131 VM_Warning("setsize: can not modify world entity\n");
134 if (e->priv.server->free)
136 VM_Warning("setsize: can not modify free entity\n");
139 min = PRVM_G_VECTOR(OFS_PARM1);
140 max = PRVM_G_VECTOR(OFS_PARM2);
142 SetMinMaxSize( e, min, max );
147 // #8 void(entity e, float chan, string samp, float volume, float atten) sound
148 static void VM_CL_sound (void)
152 prvm_edict_t *entity;
156 VM_SAFEPARMCOUNT(5, VM_CL_sound);
158 entity = PRVM_G_EDICT(OFS_PARM0);
159 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
160 sample = PRVM_G_STRING(OFS_PARM2);
161 volume = PRVM_G_FLOAT(OFS_PARM3);
162 attenuation = PRVM_G_FLOAT(OFS_PARM4);
164 if (volume < 0 || volume > 1)
166 VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
170 if (attenuation < 0 || attenuation > 4)
172 VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
176 if (channel < 0 || channel > 7)
178 VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
182 S_StartSound(32768 + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), entity->fields.client->origin, volume, attenuation);
185 // #483 void(vector origin, string sample, float volume, float attenuation) pointsound
186 static void VM_CL_pointsound(void)
193 VM_SAFEPARMCOUNT(4, VM_CL_pointsound);
195 VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org);
196 sample = PRVM_G_STRING(OFS_PARM1);
197 volume = PRVM_G_FLOAT(OFS_PARM2);
198 attenuation = PRVM_G_FLOAT(OFS_PARM3);
200 if (volume < 0 || volume > 1)
202 VM_Warning("VM_CL_pointsound: volume must be in range 0-1\n");
206 if (attenuation < 0 || attenuation > 4)
208 VM_Warning("VM_CL_pointsound: attenuation must be in range 0-4\n");
212 // Send World Entity as Entity to Play Sound (for CSQC, that is 32768)
213 S_StartSound(32768, 0, S_FindName(sample), org, volume, attenuation);
216 // #14 entity() spawn
217 static void VM_CL_spawn (void)
220 ed = PRVM_ED_Alloc();
224 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
225 static void VM_CL_traceline (void)
232 VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
234 prog->xfunction->builtinsprofile += 30;
236 v1 = PRVM_G_VECTOR(OFS_PARM0);
237 v2 = PRVM_G_VECTOR(OFS_PARM1);
238 move = (int)PRVM_G_FLOAT(OFS_PARM2);
239 ent = PRVM_G_EDICT(OFS_PARM3);
241 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]))
242 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));
244 trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
246 VM_SetTraceGlobals(&trace);
253 Used for use tracing and shot targeting
254 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
255 if the tryents flag is set.
257 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
260 // LordHavoc: added this for my own use, VERY useful, similar to traceline
261 static void VM_CL_tracebox (void)
263 float *v1, *v2, *m1, *m2;
268 VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
270 prog->xfunction->builtinsprofile += 30;
272 v1 = PRVM_G_VECTOR(OFS_PARM0);
273 m1 = PRVM_G_VECTOR(OFS_PARM1);
274 m2 = PRVM_G_VECTOR(OFS_PARM2);
275 v2 = PRVM_G_VECTOR(OFS_PARM3);
276 move = (int)PRVM_G_FLOAT(OFS_PARM4);
277 ent = PRVM_G_EDICT(OFS_PARM5);
279 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]))
280 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));
282 trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
284 VM_SetTraceGlobals(&trace);
287 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
292 vec3_t original_origin;
293 vec3_t original_velocity;
294 vec3_t original_angles;
295 vec3_t original_avelocity;
299 VectorCopy(tossent->fields.client->origin , original_origin );
300 VectorCopy(tossent->fields.client->velocity , original_velocity );
301 VectorCopy(tossent->fields.client->angles , original_angles );
302 VectorCopy(tossent->fields.client->avelocity, original_avelocity);
304 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
305 if (val != NULL && val->_float != 0)
306 gravity = val->_float;
309 gravity *= cl.movevars_gravity * 0.05;
311 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
313 tossent->fields.client->velocity[2] -= gravity;
314 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
315 VectorScale (tossent->fields.client->velocity, 0.05, move);
316 VectorAdd (tossent->fields.client->origin, move, end);
317 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);
318 VectorCopy (trace.endpos, tossent->fields.client->origin);
320 if (trace.fraction < 1)
324 VectorCopy(original_origin , tossent->fields.client->origin );
325 VectorCopy(original_velocity , tossent->fields.client->velocity );
326 VectorCopy(original_angles , tossent->fields.client->angles );
327 VectorCopy(original_avelocity, tossent->fields.client->avelocity);
332 static void VM_CL_tracetoss (void)
336 prvm_edict_t *ignore;
338 prog->xfunction->builtinsprofile += 600;
340 VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
342 ent = PRVM_G_EDICT(OFS_PARM0);
343 if (ent == prog->edicts)
345 VM_Warning("tracetoss: can not use world entity\n");
348 ignore = PRVM_G_EDICT(OFS_PARM1);
350 trace = CL_Trace_Toss (ent, ignore);
352 VM_SetTraceGlobals(&trace);
356 // #20 void(string s) precache_model
357 void VM_CL_precache_model (void)
363 VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
365 name = PRVM_G_STRING(OFS_PARM0);
366 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
368 if(!strcmp(cl.csqc_model_precache[i]->name, name))
370 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
374 PRVM_G_FLOAT(OFS_RETURN) = 0;
375 m = Mod_ForName(name, false, false, false);
378 for (i = 0;i < MAX_MODELS;i++)
380 if (!cl.csqc_model_precache[i])
382 cl.csqc_model_precache[i] = (model_t*)m;
383 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
387 VM_Warning("VM_CL_precache_model: no free models\n");
390 VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
393 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
398 ent = PRVM_NEXT_EDICT(prog->edicts);
399 for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
401 if (ent->priv.required->free)
403 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
409 // #22 entity(vector org, float rad) findradius
410 static void VM_CL_findradius (void)
412 prvm_edict_t *ent, *chain;
413 vec_t radius, radius2;
414 vec3_t org, eorg, mins, maxs;
415 int i, numtouchedicts;
416 prvm_edict_t *touchedicts[MAX_EDICTS];
418 VM_SAFEPARMCOUNT(2, VM_CL_findradius);
420 chain = (prvm_edict_t *)prog->edicts;
422 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
423 radius = PRVM_G_FLOAT(OFS_PARM1);
424 radius2 = radius * radius;
426 mins[0] = org[0] - (radius + 1);
427 mins[1] = org[1] - (radius + 1);
428 mins[2] = org[2] - (radius + 1);
429 maxs[0] = org[0] + (radius + 1);
430 maxs[1] = org[1] + (radius + 1);
431 maxs[2] = org[2] + (radius + 1);
432 numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
433 if (numtouchedicts > MAX_EDICTS)
435 // this never happens //[515]: for what then ?
436 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
437 numtouchedicts = MAX_EDICTS;
439 for (i = 0;i < numtouchedicts;i++)
441 ent = touchedicts[i];
442 // Quake did not return non-solid entities but darkplaces does
443 // (note: this is the reason you can't blow up fallen zombies)
444 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
446 // LordHavoc: compare against bounding box rather than center so it
447 // doesn't miss large objects, and use DotProduct instead of Length
448 // for a major speedup
449 VectorSubtract(org, ent->fields.client->origin, eorg);
450 if (sv_gameplayfix_findradiusdistancetobox.integer)
452 eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
453 eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
454 eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
457 VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
458 if (DotProduct(eorg, eorg) < radius2)
460 ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
465 VM_RETURN_EDICT(chain);
468 // #34 float() droptofloor
469 static void VM_CL_droptofloor (void)
476 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
478 // assume failure if it returns early
479 PRVM_G_FLOAT(OFS_RETURN) = 0;
481 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
482 if (ent == prog->edicts)
484 VM_Warning("droptofloor: can not modify world entity\n");
487 if (ent->priv.server->free)
489 VM_Warning("droptofloor: can not modify free entity\n");
493 VectorCopy (ent->fields.client->origin, end);
496 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);
498 if (trace.fraction != 1)
500 VectorCopy (trace.endpos, ent->fields.client->origin);
501 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
502 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
503 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
504 PRVM_G_FLOAT(OFS_RETURN) = 1;
505 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
506 // ent->priv.server->suspendedinairflag = true;
510 // #35 void(float style, string value) lightstyle
511 static void VM_CL_lightstyle (void)
516 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
518 i = (int)PRVM_G_FLOAT(OFS_PARM0);
519 c = PRVM_G_STRING(OFS_PARM1);
520 if (i >= cl.max_lightstyle)
522 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
525 strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
526 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
527 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
530 // #40 float(entity e) checkbottom
531 static void VM_CL_checkbottom (void)
533 static int cs_yes, cs_no;
535 vec3_t mins, maxs, start, stop;
540 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
541 ent = PRVM_G_EDICT(OFS_PARM0);
542 PRVM_G_FLOAT(OFS_RETURN) = 0;
544 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
545 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
547 // if all of the points under the corners are solid world, don't bother
548 // with the tougher checks
549 // the corners must be within 16 of the midpoint
550 start[2] = mins[2] - 1;
551 for (x=0 ; x<=1 ; x++)
552 for (y=0 ; y<=1 ; y++)
554 start[0] = x ? maxs[0] : mins[0];
555 start[1] = y ? maxs[1] : mins[1];
556 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
561 PRVM_G_FLOAT(OFS_RETURN) = true;
562 return; // we got out easy
567 // check it for real...
571 // the midpoint must be within 16 of the bottom
572 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
573 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
574 stop[2] = start[2] - 2*sv_stepheight.value;
575 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
577 if (trace.fraction == 1.0)
580 mid = bottom = trace.endpos[2];
582 // the corners must be within 16 of the midpoint
583 for (x=0 ; x<=1 ; x++)
584 for (y=0 ; y<=1 ; y++)
586 start[0] = stop[0] = x ? maxs[0] : mins[0];
587 start[1] = stop[1] = y ? maxs[1] : mins[1];
589 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
591 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
592 bottom = trace.endpos[2];
593 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
598 PRVM_G_FLOAT(OFS_RETURN) = true;
601 // #41 float(vector v) pointcontents
602 static void VM_CL_pointcontents (void)
604 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
605 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
608 // #48 void(vector o, vector d, float color, float count) particle
609 static void VM_CL_particle (void)
614 VM_SAFEPARMCOUNT(4, VM_CL_particle);
616 org = PRVM_G_VECTOR(OFS_PARM0);
617 dir = PRVM_G_VECTOR(OFS_PARM1);
618 color = (int)PRVM_G_FLOAT(OFS_PARM2);
619 count = (int)PRVM_G_FLOAT(OFS_PARM3);
620 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
623 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
624 static void VM_CL_ambientsound (void)
628 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
629 s = S_FindName(PRVM_G_STRING(OFS_PARM0));
630 f = PRVM_G_VECTOR(OFS_PARM1);
631 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
634 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
635 static void VM_CL_getlight (void)
637 vec3_t ambientcolor, diffusecolor, diffusenormal;
640 VM_SAFEPARMCOUNT(1, VM_CL_getlight);
642 p = PRVM_G_VECTOR(OFS_PARM0);
643 VectorClear(ambientcolor);
644 VectorClear(diffusecolor);
645 VectorClear(diffusenormal);
646 if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
647 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
648 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
652 //============================================================================
653 //[515]: SCENE MANAGER builtins
654 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
656 static void CSQC_R_RecalcView (void)
658 extern matrix4x4_t viewmodelmatrix;
659 Matrix4x4_CreateFromQuakeEntity(&r_refdef.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);
660 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);
663 void CL_RelinkLightFlashes(void);
664 //#300 void() clearscene (EXT_CSQC)
665 void VM_CL_R_ClearScene (void)
667 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
668 // clear renderable entity and light lists
669 r_refdef.scene.numentities = 0;
670 r_refdef.scene.numlights = 0;
671 // FIXME: restore these to the values from VM_CL_UpdateView
675 r_refdef.view.width = vid.width;
676 r_refdef.view.height = vid.height;
677 r_refdef.view.depth = 1;
678 // FIXME: restore frustum_x/frustum_y
679 r_refdef.view.useperspective = true;
680 r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
681 r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
682 r_refdef.view.frustum_x *= r_refdef.frustumscale_x;
683 r_refdef.view.frustum_y *= r_refdef.frustumscale_y;
684 r_refdef.view.ortho_x = scr_fov.value * (3.0 / 4.0) * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
685 r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
686 // FIXME: restore cl.csqc_origin
687 // FIXME: restore cl.csqc_angles
688 cl.csqc_vidvars.drawworld = true;
689 cl.csqc_vidvars.drawenginesbar = false;
690 cl.csqc_vidvars.drawcrosshair = false;
693 //#301 void(float mask) addentities (EXT_CSQC)
694 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
695 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
696 void VM_CL_R_AddEntities (void)
700 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
701 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
702 CSQC_RelinkAllEntities(drawmask);
703 CL_RelinkLightFlashes();
705 prog->globals.client->time = cl.time;
706 for(i=1;i<prog->num_edicts;i++)
708 ed = &prog->edicts[i];
709 if(ed->priv.required->free)
712 if(ed->priv.required->free)
714 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
716 if(ed->priv.required->free)
718 if(!((int)ed->fields.client->drawmask & drawmask))
720 CSQC_AddRenderEdict(ed);
724 //#302 void(entity ent) addentity (EXT_CSQC)
725 void VM_CL_R_AddEntity (void)
727 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
728 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
731 //#303 float(float property, ...) setproperty (EXT_CSQC)
732 void VM_CL_R_SetView (void)
738 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
740 c = (int)PRVM_G_FLOAT(OFS_PARM0);
741 f = PRVM_G_VECTOR(OFS_PARM1);
742 k = PRVM_G_FLOAT(OFS_PARM1);
747 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
748 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
751 r_refdef.view.x = (int)(k * vid.width / vid_conwidth.value);
754 r_refdef.view.y = (int)(k * vid.height / vid_conheight.value);
757 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
758 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
761 r_refdef.view.width = (int)(k * vid.width / vid_conwidth.value);
764 r_refdef.view.height = (int)(k * vid.height / vid_conheight.value);
767 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
768 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
769 f = PRVM_G_VECTOR(OFS_PARM2);
770 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
771 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
774 r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
775 r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
778 r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
781 r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
784 VectorCopy(f, cl.csqc_origin);
788 cl.csqc_origin[0] = k;
792 cl.csqc_origin[1] = k;
796 cl.csqc_origin[2] = k;
800 VectorCopy(f, cl.csqc_angles);
804 cl.csqc_angles[0] = k;
808 cl.csqc_angles[1] = k;
812 cl.csqc_angles[2] = k;
816 cl.csqc_vidvars.drawworld = k;
818 case VF_DRAWENGINESBAR:
819 cl.csqc_vidvars.drawenginesbar = k;
821 case VF_DRAWCROSSHAIR:
822 cl.csqc_vidvars.drawcrosshair = k;
824 case VF_CL_VIEWANGLES:
825 VectorCopy(f, cl.viewangles);
827 case VF_CL_VIEWANGLES_X:
828 cl.viewangles[0] = k;
830 case VF_CL_VIEWANGLES_Y:
831 cl.viewangles[1] = k;
833 case VF_CL_VIEWANGLES_Z:
834 cl.viewangles[2] = k;
837 r_refdef.view.useperspective = k != 0;
840 PRVM_G_FLOAT(OFS_RETURN) = 0;
841 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
844 PRVM_G_FLOAT(OFS_RETURN) = 1;
847 //#304 void() renderscene (EXT_CSQC)
848 void VM_CL_R_RenderScene (void)
850 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
851 // we need to update any RENDER_VIEWMODEL entities at this point because
852 // csqc supplies its own view matrix
853 CL_UpdateViewEntities();
858 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
859 void VM_CL_R_AddDynamicLight (void)
863 VM_SAFEPARMCOUNTRANGE(3, 3, VM_CL_R_AddDynamicLight);
865 // if we've run out of dlights, just return
866 if (r_refdef.scene.numlights >= MAX_DLIGHTS)
869 pos = PRVM_G_VECTOR(OFS_PARM0);
870 col = PRVM_G_VECTOR(OFS_PARM2);
871 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
872 R_RTLight_Update(&r_refdef.scene.lights[r_refdef.scene.numlights++], false, &matrix, col, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
875 //============================================================================
877 //#310 vector (vector v) cs_unproject (EXT_CSQC)
878 static void VM_CL_unproject (void)
883 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
884 f = PRVM_G_VECTOR(OFS_PARM0);
885 VectorSet(temp, f[2], f[0] * f[2] * -r_refdef.view.frustum_x * 2.0 / r_refdef.view.width, f[1] * f[2] * -r_refdef.view.frustum_y * 2.0 / r_refdef.view.height);
886 Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
889 //#311 vector (vector v) cs_project (EXT_CSQC)
890 static void VM_CL_project (void)
896 VM_SAFEPARMCOUNT(1, VM_CL_project);
897 f = PRVM_G_VECTOR(OFS_PARM0);
898 Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
899 Matrix4x4_Transform(&m, f, v);
900 VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_refdef.view.frustum_x*0.5*r_refdef.view.width, v[2]/v[0]/-r_refdef.view.frustum_y*r_refdef.view.height*0.5, v[0]);
903 //#330 float(float stnum) getstatf (EXT_CSQC)
904 static void VM_CL_getstatf (void)
912 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
913 i = (int)PRVM_G_FLOAT(OFS_PARM0);
914 if(i < 0 || i >= MAX_CL_STATS)
916 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
920 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
923 //#331 float(float stnum) getstati (EXT_CSQC)
924 static void VM_CL_getstati (void)
927 int firstbit, bitcount;
929 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
931 index = (int)PRVM_G_FLOAT(OFS_PARM0);
934 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
936 bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
946 if(index < 0 || index >= MAX_CL_STATS)
948 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
952 if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from.
953 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
954 PRVM_G_FLOAT(OFS_RETURN) = i;
957 //#332 string(float firststnum) getstats (EXT_CSQC)
958 static void VM_CL_getstats (void)
962 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
963 i = (int)PRVM_G_FLOAT(OFS_PARM0);
964 if(i < 0 || i > MAX_CL_STATS-4)
966 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
967 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
970 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
971 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
974 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
975 static void VM_CL_setmodelindex (void)
979 struct model_s *model;
981 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
983 t = PRVM_G_EDICT(OFS_PARM0);
985 i = (int)PRVM_G_FLOAT(OFS_PARM1);
987 t->fields.client->model = 0;
988 t->fields.client->modelindex = 0;
993 model = CL_GetModelByIndex(i);
996 VM_Warning("VM_CL_setmodelindex: null model\n");
999 t->fields.client->model = PRVM_SetEngineString(model->name);
1000 t->fields.client->modelindex = i;
1002 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
1005 SetMinMaxSize (t, model->normalmins, model->normalmaxs);
1008 SetMinMaxSize (t, vec3_origin, vec3_origin);
1011 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
1012 static void VM_CL_modelnameforindex (void)
1016 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
1018 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1019 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
1020 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
1023 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
1024 static void VM_CL_particleeffectnum (void)
1027 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
1028 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
1031 PRVM_G_FLOAT(OFS_RETURN) = i;
1034 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
1035 static void VM_CL_trailparticles (void)
1040 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
1042 t = PRVM_G_EDICT(OFS_PARM0);
1043 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1044 start = PRVM_G_VECTOR(OFS_PARM2);
1045 end = PRVM_G_VECTOR(OFS_PARM3);
1047 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);
1050 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
1051 static void VM_CL_pointparticles (void)
1055 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
1056 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1057 f = PRVM_G_VECTOR(OFS_PARM1);
1058 v = PRVM_G_VECTOR(OFS_PARM2);
1059 n = (int)PRVM_G_FLOAT(OFS_PARM3);
1060 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1063 //#342 string(float keynum) getkeybind (EXT_CSQC)
1064 static void VM_CL_getkeybind (void)
1066 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
1067 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
1070 //#343 void(float usecursor) setcursormode (EXT_CSQC)
1071 static void VM_CL_setcursormode (void)
1073 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
1074 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
1075 cl_ignoremousemoves = 2;
1078 //#345 float(float framenum) getinputstate (EXT_CSQC)
1079 static void VM_CL_getinputstate (void)
1082 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1083 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1084 for (i = 0;i < cl.movement_numqueue;i++)
1085 if (cl.movement_queue[i].sequence == frame)
1087 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
1088 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
1089 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
1090 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
1091 if(cl.movement_queue[i].crouch)
1093 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1094 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1098 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1099 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1104 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1105 static void VM_CL_setsensitivityscale (void)
1107 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1108 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1111 //#347 void() runstandardplayerphysics (EXT_CSQC)
1112 static void VM_CL_runplayerphysics (void)
1116 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1117 static void VM_CL_getplayerkey (void)
1123 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1125 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1126 c = PRVM_G_STRING(OFS_PARM1);
1127 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1130 i = Sbar_GetPlayer(i);
1136 if(!strcasecmp(c, "name"))
1137 strlcpy(t, cl.scores[i].name, sizeof(t));
1139 if(!strcasecmp(c, "frags"))
1140 sprintf(t, "%i", cl.scores[i].frags);
1142 if(!strcasecmp(c, "ping"))
1143 sprintf(t, "%i", cl.scores[i].qw_ping);
1145 if(!strcasecmp(c, "pl"))
1146 sprintf(t, "%i", cl.scores[i].qw_packetloss);
1148 if(!strcasecmp(c, "entertime"))
1149 sprintf(t, "%f", cl.scores[i].qw_entertime);
1151 if(!strcasecmp(c, "colors"))
1152 sprintf(t, "%i", cl.scores[i].colors);
1154 if(!strcasecmp(c, "topcolor"))
1155 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1157 if(!strcasecmp(c, "bottomcolor"))
1158 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1160 if(!strcasecmp(c, "viewentity"))
1161 sprintf(t, "%i", i+1);
1164 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1167 //#349 float() isdemo (EXT_CSQC)
1168 static void VM_CL_isdemo (void)
1170 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1171 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1174 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1175 static void VM_CL_setlistener (void)
1177 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1178 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));
1179 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1182 //#352 void(string cmdname) registercommand (EXT_CSQC)
1183 static void VM_CL_registercmd (void)
1186 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1187 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1191 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1192 t = (char *)Z_Malloc(alloclen);
1193 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1194 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1197 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1201 //#360 float() readbyte (EXT_CSQC)
1202 static void VM_CL_ReadByte (void)
1204 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1205 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1208 //#361 float() readchar (EXT_CSQC)
1209 static void VM_CL_ReadChar (void)
1211 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1212 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1215 //#362 float() readshort (EXT_CSQC)
1216 static void VM_CL_ReadShort (void)
1218 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1219 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1222 //#363 float() readlong (EXT_CSQC)
1223 static void VM_CL_ReadLong (void)
1225 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1226 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1229 //#364 float() readcoord (EXT_CSQC)
1230 static void VM_CL_ReadCoord (void)
1232 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1233 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1236 //#365 float() readangle (EXT_CSQC)
1237 static void VM_CL_ReadAngle (void)
1239 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1240 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1243 //#366 string() readstring (EXT_CSQC)
1244 static void VM_CL_ReadString (void)
1246 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1247 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1250 //#367 float() readfloat (EXT_CSQC)
1251 static void VM_CL_ReadFloat (void)
1253 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1254 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1257 //////////////////////////////////////////////////////////
1259 static void VM_CL_makestatic (void)
1263 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1265 ent = PRVM_G_EDICT(OFS_PARM0);
1266 if (ent == prog->edicts)
1268 VM_Warning("makestatic: can not modify world entity\n");
1271 if (ent->priv.server->free)
1273 VM_Warning("makestatic: can not modify free entity\n");
1277 if (cl.num_static_entities < cl.max_static_entities)
1281 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1283 // copy it to the current state
1284 memset(staticent, 0, sizeof(*staticent));
1285 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1286 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1287 staticent->render.framelerp = 0;
1288 // make torchs play out of sync
1289 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1290 staticent->render.skinnum = (int)ent->fields.client->skin;
1291 staticent->render.effects = (int)ent->fields.client->effects;
1292 staticent->render.alpha = 1;
1293 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1294 staticent->render.scale = 1;
1295 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1296 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1299 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1300 if (renderflags & RF_USEAXIS)
1303 VectorNegate(prog->globals.client->v_right, left);
1304 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1305 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1308 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);
1310 // either fullbright or lit
1311 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1312 staticent->render.flags |= RENDER_LIGHT;
1313 // turn off shadows from transparent objects
1314 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1315 staticent->render.flags |= RENDER_SHADOW;
1317 CL_UpdateRenderEntity(&staticent->render);
1320 Con_Printf("Too many static entities");
1322 // throw the entity away now
1326 //=================================================================//
1332 copies data from one entity to another
1334 copyentity(src, dst)
1337 static void VM_CL_copyentity (void)
1339 prvm_edict_t *in, *out;
1340 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1341 in = PRVM_G_EDICT(OFS_PARM0);
1342 if (in == prog->edicts)
1344 VM_Warning("copyentity: can not read world entity\n");
1347 if (in->priv.server->free)
1349 VM_Warning("copyentity: can not read free entity\n");
1352 out = PRVM_G_EDICT(OFS_PARM1);
1353 if (out == prog->edicts)
1355 VM_Warning("copyentity: can not modify world entity\n");
1358 if (out->priv.server->free)
1360 VM_Warning("copyentity: can not modify free entity\n");
1363 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1367 //=================================================================//
1369 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1370 static void VM_CL_effect (void)
1372 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1373 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));
1376 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1377 static void VM_CL_te_blood (void)
1381 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1382 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1384 pos = PRVM_G_VECTOR(OFS_PARM0);
1385 CL_FindNonSolidLocation(pos, pos2, 4);
1386 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1389 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1390 static void VM_CL_te_bloodshower (void)
1394 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1395 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1397 speed = PRVM_G_FLOAT(OFS_PARM2);
1404 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1407 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1408 static void VM_CL_te_explosionrgb (void)
1412 matrix4x4_t tempmatrix;
1413 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1414 pos = PRVM_G_VECTOR(OFS_PARM0);
1415 CL_FindNonSolidLocation(pos, pos2, 10);
1416 CL_ParticleExplosion(pos2);
1417 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1418 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);
1421 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1422 static void VM_CL_te_particlecube (void)
1424 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1425 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));
1428 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1429 static void VM_CL_te_particlerain (void)
1431 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1432 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);
1435 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1436 static void VM_CL_te_particlesnow (void)
1438 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1439 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);
1442 // #411 void(vector org, vector vel, float howmany) te_spark
1443 static void VM_CL_te_spark (void)
1447 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1449 pos = PRVM_G_VECTOR(OFS_PARM0);
1450 CL_FindNonSolidLocation(pos, pos2, 4);
1451 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1454 extern cvar_t cl_sound_ric_gunshot;
1455 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1456 static void VM_CL_te_gunshotquad (void)
1461 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1463 pos = PRVM_G_VECTOR(OFS_PARM0);
1464 CL_FindNonSolidLocation(pos, pos2, 4);
1465 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1466 if(cl_sound_ric_gunshot.integer >= 2)
1468 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1472 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1473 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1474 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1479 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1480 static void VM_CL_te_spikequad (void)
1485 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1487 pos = PRVM_G_VECTOR(OFS_PARM0);
1488 CL_FindNonSolidLocation(pos, pos2, 4);
1489 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1490 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1494 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1495 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1496 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1500 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1501 static void VM_CL_te_superspikequad (void)
1506 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1508 pos = PRVM_G_VECTOR(OFS_PARM0);
1509 CL_FindNonSolidLocation(pos, pos2, 4);
1510 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1511 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1515 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1516 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1517 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1521 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1522 static void VM_CL_te_explosionquad (void)
1526 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1528 pos = PRVM_G_VECTOR(OFS_PARM0);
1529 CL_FindNonSolidLocation(pos, pos2, 10);
1530 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1531 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1534 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1535 static void VM_CL_te_smallflash (void)
1539 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1541 pos = PRVM_G_VECTOR(OFS_PARM0);
1542 CL_FindNonSolidLocation(pos, pos2, 10);
1543 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1546 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1547 static void VM_CL_te_customflash (void)
1551 matrix4x4_t tempmatrix;
1552 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1554 pos = PRVM_G_VECTOR(OFS_PARM0);
1555 CL_FindNonSolidLocation(pos, pos2, 4);
1556 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1557 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);
1560 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1561 static void VM_CL_te_gunshot (void)
1566 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1568 pos = PRVM_G_VECTOR(OFS_PARM0);
1569 CL_FindNonSolidLocation(pos, pos2, 4);
1570 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1571 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1573 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1577 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1578 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1579 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1584 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1585 static void VM_CL_te_spike (void)
1590 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1592 pos = PRVM_G_VECTOR(OFS_PARM0);
1593 CL_FindNonSolidLocation(pos, pos2, 4);
1594 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1595 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1599 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1600 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1601 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1605 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1606 static void VM_CL_te_superspike (void)
1611 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1613 pos = PRVM_G_VECTOR(OFS_PARM0);
1614 CL_FindNonSolidLocation(pos, pos2, 4);
1615 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1616 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1620 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1621 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1622 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1626 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1627 static void VM_CL_te_explosion (void)
1631 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1633 pos = PRVM_G_VECTOR(OFS_PARM0);
1634 CL_FindNonSolidLocation(pos, pos2, 10);
1635 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1636 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1639 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1640 static void VM_CL_te_tarexplosion (void)
1644 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1646 pos = PRVM_G_VECTOR(OFS_PARM0);
1647 CL_FindNonSolidLocation(pos, pos2, 10);
1648 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1649 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1652 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1653 static void VM_CL_te_wizspike (void)
1657 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1659 pos = PRVM_G_VECTOR(OFS_PARM0);
1660 CL_FindNonSolidLocation(pos, pos2, 4);
1661 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1662 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1665 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1666 static void VM_CL_te_knightspike (void)
1670 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1672 pos = PRVM_G_VECTOR(OFS_PARM0);
1673 CL_FindNonSolidLocation(pos, pos2, 4);
1674 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1675 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1678 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1679 static void VM_CL_te_lavasplash (void)
1681 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1682 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1685 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1686 static void VM_CL_te_teleport (void)
1688 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1689 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1692 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1693 static void VM_CL_te_explosion2 (void)
1697 matrix4x4_t tempmatrix;
1698 int colorStart, colorLength;
1699 unsigned char *tempcolor;
1700 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1702 pos = PRVM_G_VECTOR(OFS_PARM0);
1703 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1704 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1705 CL_FindNonSolidLocation(pos, pos2, 10);
1706 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1707 tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
1708 color[0] = tempcolor[0] * (2.0f / 255.0f);
1709 color[1] = tempcolor[1] * (2.0f / 255.0f);
1710 color[2] = tempcolor[2] * (2.0f / 255.0f);
1711 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1712 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);
1713 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1717 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1718 static void VM_CL_te_lightning1 (void)
1720 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1721 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1724 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1725 static void VM_CL_te_lightning2 (void)
1727 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1728 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1731 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1732 static void VM_CL_te_lightning3 (void)
1734 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1735 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1738 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1739 static void VM_CL_te_beam (void)
1741 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1742 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1745 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1746 static void VM_CL_te_plasmaburn (void)
1750 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1752 pos = PRVM_G_VECTOR(OFS_PARM0);
1753 CL_FindNonSolidLocation(pos, pos2, 4);
1754 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1757 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1758 static void VM_CL_te_flamejet (void)
1762 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1763 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1765 pos = PRVM_G_VECTOR(OFS_PARM0);
1766 CL_FindNonSolidLocation(pos, pos2, 4);
1767 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1771 //====================================================================
1774 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1776 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1778 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1780 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1783 // #434 float(entity e, float s) getsurfacenumpoints
1784 static void VM_CL_getsurfacenumpoints(void)
1787 msurface_t *surface;
1788 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1789 // return 0 if no such surface
1790 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1792 PRVM_G_FLOAT(OFS_RETURN) = 0;
1796 // note: this (incorrectly) assumes it is a simple polygon
1797 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1800 // #435 vector(entity e, float s, float n) getsurfacepoint
1801 static void VM_CL_getsurfacepoint(void)
1805 msurface_t *surface;
1807 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1808 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1809 ed = PRVM_G_EDICT(OFS_PARM0);
1810 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1812 // note: this (incorrectly) assumes it is a simple polygon
1813 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1814 if (pointnum < 0 || pointnum >= surface->num_vertices)
1816 // FIXME: implement rotation/scaling
1817 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1819 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
1820 // float SPA_POSITION = 0;
1821 // float SPA_S_AXIS = 1;
1822 // float SPA_T_AXIS = 2;
1823 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1824 // float SPA_TEXCOORDS0 = 4;
1825 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1826 // float SPA_LIGHTMAP0_COLOR = 6;
1827 // TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black]
1828 static void VM_CL_getsurfacepointattribute(void)
1832 msurface_t *surface;
1836 VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints);
1837 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1838 ed = PRVM_G_EDICT(OFS_PARM0);
1839 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1841 // note: this (incorrectly) assumes it is a simple polygon
1842 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1843 if (pointnum < 0 || pointnum >= surface->num_vertices)
1846 // FIXME: implement rotation/scaling
1847 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
1849 switch( attributetype ) {
1850 // float SPA_POSITION = 0;
1852 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1854 // float SPA_S_AXIS = 1;
1856 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1858 // float SPA_T_AXIS = 2;
1860 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1862 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1864 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1866 // float SPA_TEXCOORDS0 = 4;
1868 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1869 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
1870 ret[0] = texcoord[0];
1871 ret[1] = texcoord[1];
1875 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1877 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1878 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
1879 ret[0] = texcoord[0];
1880 ret[1] = texcoord[1];
1884 // float SPA_LIGHTMAP0_COLOR = 6;
1886 // ignore alpha for now..
1887 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
1890 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
1894 // #436 vector(entity e, float s) getsurfacenormal
1895 static void VM_CL_getsurfacenormal(void)
1898 msurface_t *surface;
1900 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1901 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1902 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1904 // FIXME: implement rotation/scaling
1905 // note: this (incorrectly) assumes it is a simple polygon
1906 // note: this only returns the first triangle, so it doesn't work very
1907 // well for curved surfaces or arbitrary meshes
1908 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);
1909 VectorNormalize(normal);
1910 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1913 // #437 string(entity e, float s) getsurfacetexture
1914 static void VM_CL_getsurfacetexture(void)
1917 msurface_t *surface;
1918 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1919 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1920 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1922 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1925 // #438 float(entity e, vector p) getsurfacenearpoint
1926 static void VM_CL_getsurfacenearpoint(void)
1928 int surfacenum, best;
1930 vec_t dist, bestdist;
1932 model_t *model = NULL;
1933 msurface_t *surface;
1935 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1936 PRVM_G_FLOAT(OFS_RETURN) = -1;
1937 ed = PRVM_G_EDICT(OFS_PARM0);
1938 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1941 // FIXME: implement rotation/scaling
1942 point = PRVM_G_VECTOR(OFS_PARM1);
1943 VectorSubtract(point, ed->fields.client->origin, p);
1945 bestdist = 1000000000;
1946 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1948 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1949 // first see if the nearest point on the surface's box is closer than the previous match
1950 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1951 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1952 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1953 dist = VectorLength2(clipped);
1954 if (dist < bestdist)
1956 // it is, check the nearest point on the actual geometry
1957 clippointtosurface(model, surface, p, clipped);
1958 VectorSubtract(clipped, p, clipped);
1959 dist += VectorLength2(clipped);
1960 if (dist < bestdist)
1962 // that's closer too, store it as the best match
1968 PRVM_G_FLOAT(OFS_RETURN) = best;
1971 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1972 static void VM_CL_getsurfaceclippedpoint(void)
1976 msurface_t *surface;
1978 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1979 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1980 ed = PRVM_G_EDICT(OFS_PARM0);
1981 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1983 // FIXME: implement rotation/scaling
1984 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1985 clippointtosurface(model, surface, p, out);
1986 // FIXME: implement rotation/scaling
1987 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1990 // #443 void(entity e, entity tagentity, string tagname) setattachment
1991 static void VM_CL_setattachment (void)
1994 prvm_edict_t *tagentity;
1995 const char *tagname;
1999 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
2001 e = PRVM_G_EDICT(OFS_PARM0);
2002 tagentity = PRVM_G_EDICT(OFS_PARM1);
2003 tagname = PRVM_G_STRING(OFS_PARM2);
2005 if (e == prog->edicts)
2007 VM_Warning("setattachment: can not modify world entity\n");
2010 if (e->priv.server->free)
2012 VM_Warning("setattachment: can not modify free entity\n");
2016 if (tagentity == NULL)
2017 tagentity = prog->edicts;
2019 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2021 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2023 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2026 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2028 modelindex = (int)tagentity->fields.client->modelindex;
2029 model = CL_GetModelByIndex(modelindex);
2032 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
2034 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);
2037 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));
2041 /////////////////////////////////////////
2042 // DP_MD3_TAGINFO extension coded by VorteX
2044 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
2046 model_t *model = CL_GetModelFromEdict(e);
2048 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
2053 // Warnings/errors code:
2054 // 0 - normal (everything all-right)
2057 // 3 - null or non-precached model
2058 // 4 - no tags with requested index
2059 // 5 - runaway loop at attachment chain
2060 extern cvar_t cl_bob;
2061 extern cvar_t cl_bobcycle;
2062 extern cvar_t cl_bobup;
2063 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2066 int reqframe, attachloop;
2067 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2068 prvm_edict_t *attachent;
2072 *out = identitymatrix; // warnings and errors return identical matrix
2074 if (ent == prog->edicts)
2076 if (ent->priv.server->free)
2079 model = CL_GetModelFromEdict(ent);
2084 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
2085 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
2087 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2089 // get initial tag matrix
2092 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2097 tagmatrix = identitymatrix;
2099 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2100 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2104 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2105 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
2107 model = CL_GetModelFromEdict(attachent);
2109 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
2110 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
2112 attachmatrix = identitymatrix;
2114 // apply transformation by child entity matrix
2116 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2117 if (val && val->_float != 0)
2118 scale = val->_float;
2119 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], scale);
2120 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2121 Matrix4x4_Copy(&tagmatrix, out);
2123 // finally transformate by matrix of tag on parent entity
2124 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2125 Matrix4x4_Copy(&tagmatrix, out);
2129 if (attachloop > 255) // prevent runaway looping
2132 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
2135 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2137 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2138 if (val && val->_float != 0)
2139 scale = val->_float;
2140 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2141 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], scale);
2142 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2144 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
2145 {// RENDER_VIEWMODEL magic
2146 Matrix4x4_Copy(&tagmatrix, out);
2149 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2150 if (val && val->_float != 0)
2151 scale = val->_float;
2153 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], scale);
2154 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2157 // Cl_bob, ported from rendering code
2158 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2161 // LordHavoc: this code is *weird*, but not replacable (I think it
2162 // should be done in QC on the server, but oh well, quake is quake)
2163 // LordHavoc: figured out bobup: the time at which the sin is at 180
2164 // degrees (which allows lengthening or squishing the peak or valley)
2165 cycle = cl.time/cl_bobcycle.value;
2166 cycle -= (int)cycle;
2167 if (cycle < cl_bobup.value)
2168 cycle = sin(M_PI * cycle / cl_bobup.value);
2170 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2171 // bob is proportional to velocity in the xy plane
2172 // (don't count Z, or jumping messes it up)
2173 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;
2174 bob = bob*0.3 + bob*0.7*cycle;
2175 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2182 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2183 static void VM_CL_gettagindex (void)
2186 const char *tag_name;
2187 int modelindex, tag_index;
2189 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2191 ent = PRVM_G_EDICT(OFS_PARM0);
2192 tag_name = PRVM_G_STRING(OFS_PARM1);
2193 if (ent == prog->edicts)
2195 VM_Warning("gettagindex: can't affect world entity\n");
2198 if (ent->priv.server->free)
2200 VM_Warning("gettagindex: can't affect free entity\n");
2204 modelindex = (int)ent->fields.client->modelindex;
2206 if (modelindex >= MAX_MODELS || (modelindex <= -MAX_MODELS /* client models */))
2207 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2210 tag_index = CL_GetTagIndex(ent, tag_name);
2212 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2214 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2217 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2218 static void VM_CL_gettaginfo (void)
2222 matrix4x4_t tag_matrix;
2225 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2227 e = PRVM_G_EDICT(OFS_PARM0);
2228 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2229 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2230 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2235 VM_Warning("gettagindex: can't affect world entity\n");
2238 VM_Warning("gettagindex: can't affect free entity\n");
2241 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2244 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2247 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2252 //============================================================================
2254 //====================
2255 //QC POLYGON functions
2256 //====================
2261 float data[36]; //[515]: enough for polygons
2262 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2265 typedef struct vmpolygons_s
2267 //static float vm_polygon_linewidth = 1;
2269 unsigned char current_vertices;
2270 qboolean initialized;
2271 vm_polygon_t *polygons;
2272 unsigned long polygons_num, drawpolygons_num; //[515]: ok long on 64bit ?
2273 qboolean polygonbegin; //[515]: for "no-crap-on-the-screen" check
2275 vmpolygons_t vmpolygons[PRVM_MAXPROGS];
2276 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2278 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2279 #define VM_POLYGON_FLLINES 32
2280 #define VM_POLYGON_FL2D 64
2281 #define VM_POLYGON_FL4V 128 //4 vertices
2283 static void VM_InitPolygons (vmpolygons_t* polys)
2285 polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
2286 polys->polygons = (vm_polygon_t *)Mem_Alloc(polys->pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2287 memset(polys->polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2288 polys->polygons_num = VM_DEFPOLYNUM;
2289 polys->drawpolygons_num = 0;
2290 polys->polygonbegin = false;
2291 polys->initialized = true;
2294 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2296 int surfacelistindex;
2297 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2299 // LordHavoc: FIXME: this is stupid code
2300 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2302 const vm_polygon_t *p = &polys->polygons[surfacelist[surfacelistindex]];
2303 int flags = p->flags & 0x0f;
2305 if(flags == DRAWFLAG_ADDITIVE)
2306 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2307 else if(flags == DRAWFLAG_MODULATE)
2308 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2309 else if(flags == DRAWFLAG_2XMODULATE)
2310 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2312 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2314 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2317 //[515]: is speed is max ?
2318 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2320 qglLineWidth(p->data[13]);CHECKGLERROR
2321 qglBegin(GL_LINE_LOOP);
2322 qglTexCoord1f (p->data[12]);
2323 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2324 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2326 qglTexCoord1f (p->data[14]);
2327 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2328 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2330 if(p->flags & VM_POLYGON_FL3V)
2332 qglTexCoord1f (p->data[16]);
2333 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2334 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2336 if(p->flags & VM_POLYGON_FL4V)
2338 qglTexCoord1f (p->data[18]);
2339 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2340 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2348 qglBegin(GL_POLYGON);
2349 qglTexCoord2f (p->data[12], p->data[13]);
2350 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2351 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2353 qglTexCoord2f (p->data[14], p->data[15]);
2354 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2355 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2357 qglTexCoord2f (p->data[16], p->data[17]);
2358 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2359 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2361 if(p->flags & VM_POLYGON_FL4V)
2363 qglTexCoord2f (p->data[18], p->data[19]);
2364 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2365 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2373 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2375 drawqueuemesh_t mesh;
2376 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2377 mesh.texture = p->tex;
2378 mesh.data_element3i = picelements;
2379 mesh.data_vertex3f = p->data;
2380 mesh.data_texcoord2f = p->data + 12;
2381 mesh.data_color4f = p->data + 20;
2382 if(p->flags & VM_POLYGON_FL4V)
2384 mesh.num_vertices = 4;
2385 mesh.num_triangles = 2;
2389 mesh.num_vertices = 3;
2390 mesh.num_triangles = 1;
2392 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2393 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2395 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2398 // TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
2399 void VM_CL_AddPolygonsToMeshQueue (void)
2402 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2404 // only add polygons of the currently active prog to the queue - if there is none, we're done
2408 if(!polys->drawpolygons_num)
2410 R_Mesh_Matrix(&identitymatrix);
2411 GL_CullFace(GL_NONE);
2412 for(i = 0;i < (int)polys->drawpolygons_num;i++)
2413 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2414 polys->drawpolygons_num = 0;
2417 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2418 void VM_CL_R_PolygonBegin (void)
2421 const char *picname;
2422 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2424 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2426 if(!polys->initialized)
2427 VM_InitPolygons(polys);
2428 if(polys->polygonbegin)
2430 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2433 if(polys->drawpolygons_num >= polys->polygons_num)
2435 p = (vm_polygon_t *)Mem_Alloc(polys->pool, 2 * polys->polygons_num * sizeof(vm_polygon_t));
2436 memset(p, 0, 2 * polys->polygons_num * sizeof(vm_polygon_t));
2437 memcpy(p, polys->polygons, polys->polygons_num * sizeof(vm_polygon_t));
2438 Mem_Free(polys->polygons);
2439 polys->polygons = p;
2440 polys->polygons_num *= 2;
2442 p = &polys->polygons[polys->drawpolygons_num];
2443 picname = PRVM_G_STRING(OFS_PARM0);
2445 p->tex = Draw_CachePic(picname, true)->tex;
2447 p->tex = r_texture_white;
2448 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2449 polys->current_vertices = 0;
2450 polys->polygonbegin = true;
2453 if(PRVM_G_FLOAT(OFS_PARM2))
2454 p->flags |= VM_POLYGON_FL2D;
2455 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2457 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2458 p->flags |= VM_POLYGON_FLLINES;
2463 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2464 void VM_CL_R_PolygonVertex (void)
2466 float *coords, *tx, *rgb, alpha;
2468 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2470 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2472 if(!polys->polygonbegin)
2474 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2477 coords = PRVM_G_VECTOR(OFS_PARM0);
2478 tx = PRVM_G_VECTOR(OFS_PARM1);
2479 rgb = PRVM_G_VECTOR(OFS_PARM2);
2480 alpha = PRVM_G_FLOAT(OFS_PARM3);
2482 p = &polys->polygons[polys->drawpolygons_num];
2483 if(polys->current_vertices > 4)
2485 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2489 p->data[polys->current_vertices*3] = coords[0];
2490 p->data[1+polys->current_vertices*3] = coords[1];
2491 p->data[2+polys->current_vertices*3] = coords[2];
2493 p->data[12+polys->current_vertices*2] = tx[0];
2494 if(!(p->flags & VM_POLYGON_FLLINES))
2495 p->data[13+polys->current_vertices*2] = tx[1];
2497 p->data[20+polys->current_vertices*4] = rgb[0];
2498 p->data[21+polys->current_vertices*4] = rgb[1];
2499 p->data[22+polys->current_vertices*4] = rgb[2];
2500 p->data[23+polys->current_vertices*4] = alpha;
2502 polys->current_vertices++;
2503 if(polys->current_vertices == 4)
2504 p->flags |= VM_POLYGON_FL4V;
2506 if(polys->current_vertices == 3)
2507 p->flags |= VM_POLYGON_FL3V;
2510 //void() R_EndPolygon
2511 void VM_CL_R_PolygonEnd (void)
2513 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2515 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2516 if(!polys->polygonbegin)
2518 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2521 polys->polygonbegin = false;
2522 if(polys->current_vertices > 2 || (polys->current_vertices >= 2 && polys->polygons[polys->drawpolygons_num].flags & VM_POLYGON_FLLINES))
2524 if(polys->polygons[polys->drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2525 VM_CL_AddPolygonTo2DScene(&polys->polygons[polys->drawpolygons_num]);
2527 polys->drawpolygons_num++;
2530 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->current_vertices);
2533 static vmpolygons_t debugPolys;
2535 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2539 if(!debugPolys.initialized)
2540 VM_InitPolygons(&debugPolys);
2541 if(debugPolys.polygonbegin)
2543 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2546 // limit polygons to a vaguely sane amount, beyond this each one just
2547 // replaces the last one
2548 debugPolys.drawpolygons_num = min(debugPolys.drawpolygons_num, (1<<20)-1);
2549 if(debugPolys.drawpolygons_num >= debugPolys.polygons_num)
2551 p = (vm_polygon_t *)Mem_Alloc(debugPolys.pool, 2 * debugPolys.polygons_num * sizeof(vm_polygon_t));
2552 memset(p, 0, 2 * debugPolys.polygons_num * sizeof(vm_polygon_t));
2553 memcpy(p, debugPolys.polygons, debugPolys.polygons_num * sizeof(vm_polygon_t));
2554 Mem_Free(debugPolys.polygons);
2555 debugPolys.polygons = p;
2556 debugPolys.polygons_num *= 2;
2558 p = &debugPolys.polygons[debugPolys.drawpolygons_num];
2559 if(picname && picname[0])
2560 p->tex = Draw_CachePic(picname, true)->tex;
2562 p->tex = r_texture_white;
2564 debugPolys.current_vertices = 0;
2565 debugPolys.polygonbegin = true;
2567 p->flags |= VM_POLYGON_FL2D;
2570 p->data[13] = linewidth; //[515]: linewidth
2571 p->flags |= VM_POLYGON_FLLINES;
2575 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2579 if(!debugPolys.polygonbegin)
2581 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2585 p = &debugPolys.polygons[debugPolys.drawpolygons_num];
2586 if(debugPolys.current_vertices > 4)
2588 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2592 p->data[debugPolys.current_vertices*3] = x;
2593 p->data[1+debugPolys.current_vertices*3] = y;
2594 p->data[2+debugPolys.current_vertices*3] = z;
2596 p->data[12+debugPolys.current_vertices*2] = s;
2597 if(!(p->flags & VM_POLYGON_FLLINES))
2598 p->data[13+debugPolys.current_vertices*2] = t;
2600 p->data[20+debugPolys.current_vertices*4] = r;
2601 p->data[21+debugPolys.current_vertices*4] = g;
2602 p->data[22+debugPolys.current_vertices*4] = b;
2603 p->data[23+debugPolys.current_vertices*4] = a;
2605 debugPolys.current_vertices++;
2606 if(debugPolys.current_vertices == 4)
2607 p->flags |= VM_POLYGON_FL4V;
2609 if(debugPolys.current_vertices == 3)
2610 p->flags |= VM_POLYGON_FL3V;
2613 void Debug_PolygonEnd(void)
2615 if(!debugPolys.polygonbegin)
2617 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2620 debugPolys.polygonbegin = false;
2621 if(debugPolys.current_vertices > 2 || (debugPolys.current_vertices >= 2 && debugPolys.polygons[debugPolys.drawpolygons_num].flags & VM_POLYGON_FLLINES))
2623 if(debugPolys.polygons[debugPolys.drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2624 VM_CL_AddPolygonTo2DScene(&debugPolys.polygons[debugPolys.drawpolygons_num]);
2626 debugPolys.drawpolygons_num++;
2629 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.current_vertices);
2636 Returns false if any part of the bottom of the entity is off an edge that
2641 qboolean CL_CheckBottom (prvm_edict_t *ent)
2643 vec3_t mins, maxs, start, stop;
2648 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2649 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2651 // if all of the points under the corners are solid world, don't bother
2652 // with the tougher checks
2653 // the corners must be within 16 of the midpoint
2654 start[2] = mins[2] - 1;
2655 for (x=0 ; x<=1 ; x++)
2656 for (y=0 ; y<=1 ; y++)
2658 start[0] = x ? maxs[0] : mins[0];
2659 start[1] = y ? maxs[1] : mins[1];
2660 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2664 return true; // we got out easy
2668 // check it for real...
2672 // the midpoint must be within 16 of the bottom
2673 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2674 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2675 stop[2] = start[2] - 2*sv_stepheight.value;
2676 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2678 if (trace.fraction == 1.0)
2680 mid = bottom = trace.endpos[2];
2682 // the corners must be within 16 of the midpoint
2683 for (x=0 ; x<=1 ; x++)
2684 for (y=0 ; y<=1 ; y++)
2686 start[0] = stop[0] = x ? maxs[0] : mins[0];
2687 start[1] = stop[1] = y ? maxs[1] : mins[1];
2689 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2691 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2692 bottom = trace.endpos[2];
2693 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2704 Called by monster program code.
2705 The move will be adjusted for slopes and stairs, but if the move isn't
2706 possible, no move is done and false is returned
2709 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2712 vec3_t oldorg, neworg, end, traceendpos;
2715 prvm_edict_t *enemy;
2719 VectorCopy (ent->fields.client->origin, oldorg);
2720 VectorAdd (ent->fields.client->origin, move, neworg);
2722 // flying monsters don't step up
2723 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2725 // try one move with vertical motion, then one without
2726 for (i=0 ; i<2 ; i++)
2728 VectorAdd (ent->fields.client->origin, move, neworg);
2729 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2730 if (i == 0 && enemy != prog->edicts)
2732 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2738 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);
2740 VM_SetTraceGlobals(&trace);
2742 if (trace.fraction == 1)
2744 VectorCopy(trace.endpos, traceendpos);
2745 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2746 return false; // swim monster left water
2748 VectorCopy (traceendpos, ent->fields.client->origin);
2754 if (enemy == prog->edicts)
2761 // push down from a step height above the wished position
2762 neworg[2] += sv_stepheight.value;
2763 VectorCopy (neworg, end);
2764 end[2] -= sv_stepheight.value*2;
2766 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2768 VM_SetTraceGlobals(&trace);
2770 if (trace.startsolid)
2772 neworg[2] -= sv_stepheight.value;
2773 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2775 VM_SetTraceGlobals(&trace);
2776 if (trace.startsolid)
2779 if (trace.fraction == 1)
2781 // if monster had the ground pulled out, go ahead and fall
2782 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2784 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2787 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2791 return false; // walked off an edge
2794 // check point traces down for dangling corners
2795 VectorCopy (trace.endpos, ent->fields.client->origin);
2797 if (!CL_CheckBottom (ent))
2799 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2800 { // entity had floor mostly pulled out from underneath it
2801 // and is trying to correct
2806 VectorCopy (oldorg, ent->fields.client->origin);
2810 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2811 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2813 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2814 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2826 float(float yaw, float dist[, settrace]) walkmove
2829 static void VM_CL_walkmove (void)
2838 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2840 // assume failure if it returns early
2841 PRVM_G_FLOAT(OFS_RETURN) = 0;
2843 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2844 if (ent == prog->edicts)
2846 VM_Warning("walkmove: can not modify world entity\n");
2849 if (ent->priv.server->free)
2851 VM_Warning("walkmove: can not modify free entity\n");
2854 yaw = PRVM_G_FLOAT(OFS_PARM0);
2855 dist = PRVM_G_FLOAT(OFS_PARM1);
2856 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2858 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2861 yaw = yaw*M_PI*2 / 360;
2863 move[0] = cos(yaw)*dist;
2864 move[1] = sin(yaw)*dist;
2867 // save program state, because CL_movestep may call other progs
2868 oldf = prog->xfunction;
2869 oldself = prog->globals.client->self;
2871 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2874 // restore program state
2875 prog->xfunction = oldf;
2876 prog->globals.client->self = oldself;
2883 string(string key) serverkey
2886 void VM_CL_serverkey(void)
2888 char string[VM_STRINGTEMP_LENGTH];
2889 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2890 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2891 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2894 //============================================================================
2896 // To create a almost working builtin file from this replace:
2897 // "^NULL.*" with ""
2898 // "^{.*//.*}:Wh\(.*\)" with "\1"
2900 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
2901 // "\n\n+" with "\n\n"
2903 prvm_builtin_t vm_cl_builtins[] = {
2904 NULL, // #0 NULL function (not callable) (QUAKE)
2905 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2906 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2907 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2908 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2909 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2910 VM_break, // #6 void() break (QUAKE)
2911 VM_random, // #7 float() random (QUAKE)
2912 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2913 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2914 VM_error, // #10 void(string e) error (QUAKE)
2915 VM_objerror, // #11 void(string e) objerror (QUAKE)
2916 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2917 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2918 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2919 VM_remove, // #15 void(entity e) remove (QUAKE)
2920 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
2921 NULL, // #17 entity() checkclient (QUAKE)
2922 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2923 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2924 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2925 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2926 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2927 NULL, // #23 void(string s, ...) bprint (QUAKE)
2928 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2929 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2930 VM_ftos, // #26 string(float f) ftos (QUAKE)
2931 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2932 VM_coredump, // #28 void() coredump (QUAKE)
2933 VM_traceon, // #29 void() traceon (QUAKE)
2934 VM_traceoff, // #30 void() traceoff (QUAKE)
2935 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2936 VM_CL_walkmove, // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
2937 NULL, // #33 (QUAKE)
2938 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2939 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2940 VM_rint, // #36 float(float v) rint (QUAKE)
2941 VM_floor, // #37 float(float v) floor (QUAKE)
2942 VM_ceil, // #38 float(float v) ceil (QUAKE)
2943 NULL, // #39 (QUAKE)
2944 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2945 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2946 NULL, // #42 (QUAKE)
2947 VM_fabs, // #43 float(float f) fabs (QUAKE)
2948 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2949 VM_cvar, // #45 float(string s) cvar (QUAKE)
2950 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2951 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2952 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2953 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2954 NULL, // #50 (QUAKE)
2955 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2956 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2957 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2958 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2959 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2960 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2961 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2962 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2963 NULL, // #59 (QUAKE)
2964 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2965 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2966 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2967 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2968 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2969 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2970 NULL, // #66 (QUAKE)
2971 NULL, // #67 void(float step) movetogoal (QUAKE)
2972 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2973 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2974 NULL, // #70 void(string s) changelevel (QUAKE)
2975 NULL, // #71 (QUAKE)
2976 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2977 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2978 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2979 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2980 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2981 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2982 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2983 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2984 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2985 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2986 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2987 NULL, // #83 (QUAKE)
2988 NULL, // #84 (QUAKE)
2989 NULL, // #85 (QUAKE)
2990 NULL, // #86 (QUAKE)
2991 NULL, // #87 (QUAKE)
2992 NULL, // #88 (QUAKE)
2993 NULL, // #89 (QUAKE)
2994 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2995 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2996 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2997 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2998 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2999 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3000 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3001 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3002 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3003 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3004 // FrikaC and Telejano range #100-#199
3015 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3016 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3017 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3018 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3019 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3020 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3021 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3022 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3023 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3024 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3105 // FTEQW range #200-#299
3124 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3127 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3128 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3129 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3130 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3131 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3132 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3133 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3134 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3135 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3136 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3138 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3206 // CSQC range #300-#399
3207 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
3208 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3209 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3210 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3211 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3212 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3213 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3214 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3215 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3216 NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
3217 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3218 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3222 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3223 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3224 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3225 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3226 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3227 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3228 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3229 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3230 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3231 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3232 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3233 VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3234 NULL, // #327 // FIXME add stringwidth() here?
3235 NULL, // #328 // FIXME add drawsubpic() here?
3237 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3238 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3239 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3240 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3241 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3242 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3243 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3244 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3245 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3246 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3247 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3248 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3249 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3250 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3251 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3252 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3253 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscale (EXT_CSQC)
3254 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3255 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3256 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3257 VM_isserver, // #350 float() isserver (EXT_CSQC)
3258 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3259 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3260 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3261 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3267 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3268 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3269 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3270 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3271 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3272 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3273 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3274 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3307 // LordHavoc's range #400-#499
3308 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3309 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3310 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3311 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3312 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3313 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3314 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3315 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3316 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)
3317 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3318 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3319 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3320 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3321 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3322 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3323 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3324 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3325 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3326 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3327 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3328 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3329 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3330 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3331 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3332 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3333 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3334 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3335 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3336 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3337 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3338 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3339 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3340 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3341 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3342 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3343 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3344 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3345 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3346 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3347 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3348 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3349 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3350 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3351 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3352 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3353 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3354 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3355 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3356 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3357 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3358 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3359 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3360 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3361 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3362 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3363 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3364 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3365 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
3367 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3368 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3369 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3370 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3371 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3372 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3373 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3374 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3375 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3376 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3377 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3378 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3379 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3380 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3381 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3382 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3383 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3384 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3385 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3386 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3387 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3388 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3389 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3390 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3391 VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
3392 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3393 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3394 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
3395 VM_gecko_create, // #487 float gecko_create( string name )
3396 VM_gecko_destroy, // #488 void gecko_destroy( string name )
3397 VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI )
3398 VM_gecko_keyevent, // #490 float gecko_keyevent( string name, float key, float eventtype )
3399 VM_gecko_movemouse, // #491 void gecko_mousemove( string name, float x, float y )
3400 VM_gecko_resize, // #492 void gecko_resize( string name, float w, float h )
3401 VM_gecko_get_texture_extent, // #493 vector gecko_get_texture_extent( string name )
3410 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3412 void VM_Polygons_Reset(void)
3414 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
3416 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3417 if(polys->initialized)
3419 Mem_FreePool(&polys->pool);
3420 polys->initialized = false;
3424 void VM_CL_Cmd_Init(void)
3427 VM_Polygons_Reset();
3430 void VM_CL_Cmd_Reset(void)
3433 VM_Polygons_Reset();