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 //====================
2258 #define VMPOLYGONS_MAXPOINTS 64
2260 typedef struct vmpolygons_triangle_s
2262 rtexture_t *texture;
2265 }vmpolygons_triangle_t;
2267 typedef struct vmpolygons_s
2270 qboolean initialized;
2274 float *data_vertex3f;
2275 float *data_color4f;
2276 float *data_texcoord2f;
2280 vmpolygons_triangle_t *data_triangles;
2281 int *data_sortedelement3i;
2283 qboolean begin_active;
2284 rtexture_t *begin_texture;
2287 float begin_vertex[VMPOLYGONS_MAXPOINTS][3];
2288 float begin_color[VMPOLYGONS_MAXPOINTS][4];
2289 float begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
2292 // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
2293 vmpolygons_t vmpolygons[PRVM_MAXPROGS];
2295 static void VM_ResizePolygons(vmpolygons_t *polys)
2297 float *oldvertex3f = polys->data_vertex3f;
2298 float *oldcolor4f = polys->data_color4f;
2299 float *oldtexcoord2f = polys->data_texcoord2f;
2300 vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
2301 int *oldsortedelement3i = polys->data_sortedelement3i;
2302 polys->max_vertices = polys->max_triangles*3;
2303 polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
2304 polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
2305 polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
2306 polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
2307 polys->data_sortedelement3i = (int *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(int[3]));
2308 if (polys->num_vertices)
2310 memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
2311 memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
2312 memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
2314 if (polys->num_triangles)
2316 memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
2317 memcpy(polys->data_sortedelement3i, oldsortedelement3i, polys->num_triangles*sizeof(int[3]));
2320 Mem_Free(oldvertex3f);
2322 Mem_Free(oldcolor4f);
2324 Mem_Free(oldtexcoord2f);
2326 Mem_Free(oldtriangles);
2327 if (oldsortedelement3i)
2328 Mem_Free(oldsortedelement3i);
2331 static void VM_InitPolygons (vmpolygons_t* polys)
2333 memset(polys, 0, sizeof(*polys));
2334 polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
2335 polys->max_triangles = 1024;
2336 VM_ResizePolygons(polys);
2337 polys->initialized = true;
2340 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2342 int surfacelistindex;
2343 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2344 R_Mesh_Matrix(&identitymatrix);
2345 GL_CullFace(GL_NONE);
2346 R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
2347 R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
2348 R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
2349 R_SetupGenericShader(true);
2350 for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
2352 int numtriangles = 0;
2353 rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
2354 int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
2355 if(drawflag == DRAWFLAG_ADDITIVE)
2356 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2357 else if(drawflag == DRAWFLAG_MODULATE)
2358 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2359 else if(drawflag == DRAWFLAG_2XMODULATE)
2360 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2362 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2363 R_Mesh_TexBind(0, R_GetTexture(tex));
2365 for (;surfacelistindex < numsurfaces;surfacelistindex++)
2367 if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag)
2369 VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].element3i, polys->data_sortedelement3i + 3*numtriangles);
2372 R_Mesh_Draw(0, polys->num_vertices, numtriangles, polys->data_sortedelement3i, 0, 0);
2376 void VMPolygons_Store(vmpolygons_t *polys)
2378 if (r_refdef.draw2dstage)
2380 // draw the polygon as 2D immediately
2381 drawqueuemesh_t mesh;
2382 mesh.texture = polys->begin_texture;
2383 mesh.num_vertices = polys->begin_vertices;
2384 mesh.num_triangles = polys->begin_vertices-2;
2385 mesh.data_element3i = polygonelements;
2386 mesh.data_vertex3f = polys->begin_vertex[0];
2387 mesh.data_color4f = polys->begin_color[0];
2388 mesh.data_texcoord2f = polys->begin_texcoord[0];
2389 DrawQ_Mesh(&mesh, polys->begin_drawflag);
2393 // queue the polygon as 3D for sorted transparent rendering later
2395 if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2)
2397 polys->max_triangles *= 2;
2398 VM_ResizePolygons(polys);
2400 memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->num_vertices * sizeof(float[3]));
2401 memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->num_vertices * sizeof(float[4]));
2402 memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->num_vertices * sizeof(float[2]));
2403 for (i = 0;i < polys->begin_vertices-2;i++)
2405 polys->data_triangles[polys->num_triangles].texture = polys->begin_texture;
2406 polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag;
2407 polys->data_triangles[polys->num_triangles].element3i[0] = polys->num_vertices;
2408 polys->data_triangles[polys->num_triangles].element3i[1] = polys->num_vertices + i+1;
2409 polys->data_triangles[polys->num_triangles].element3i[2] = polys->num_vertices + i+2;
2410 polys->num_triangles++;
2412 polys->num_vertices += polys->begin_vertices;
2414 polys->begin_active = false;
2417 // TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
2418 // LordHavoc: agreed, this is a mess
2419 void VM_CL_AddPolygonsToMeshQueue (void)
2422 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2425 // only add polygons of the currently active prog to the queue - if there is none, we're done
2429 if (!polys->num_triangles)
2432 for (i = 0;i < polys->num_triangles;i++)
2434 VectorMAMAM(1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].element3i[0], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].element3i[1], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].element3i[2], center);
2435 R_MeshQueue_AddTransparent(center, VM_DrawPolygonCallback, NULL, i, NULL);
2438 polys->num_triangles = 0;
2439 polys->num_vertices = 0;
2442 //void(string texturename, float flag) R_BeginPolygon
2443 void VM_CL_R_PolygonBegin (void)
2445 const char *picname;
2446 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2448 VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
2450 if (!polys->initialized)
2451 VM_InitPolygons(polys);
2452 if (polys->begin_active)
2454 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2457 picname = PRVM_G_STRING(OFS_PARM0);
2458 polys->begin_texture = picname[0] ? Draw_CachePic(picname, true)->tex : r_texture_white;
2459 polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
2460 polys->begin_vertices = 0;
2461 polys->begin_active = true;
2464 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2465 void VM_CL_R_PolygonVertex (void)
2467 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2469 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2471 if (!polys->begin_active)
2473 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2477 if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
2479 VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2483 polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0];
2484 polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1];
2485 polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2];
2486 polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0];
2487 polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1];
2488 polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0];
2489 polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1];
2490 polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2];
2491 polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3);
2492 polys->begin_vertices++;
2495 //void() R_EndPolygon
2496 void VM_CL_R_PolygonEnd (void)
2498 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2500 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2501 if (!polys->begin_active)
2503 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2506 polys->begin_active = false;
2507 if (polys->begin_vertices >= 3)
2508 VMPolygons_Store(polys);
2510 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
2513 static vmpolygons_t debugPolys;
2515 void Debug_PolygonBegin(const char *picname, int drawflag)
2517 if(!debugPolys.initialized)
2518 VM_InitPolygons(&debugPolys);
2519 if(debugPolys.begin_active)
2521 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2524 debugPolys.begin_texture = picname[0] ? Draw_CachePic(picname, true)->tex : r_texture_white;
2525 debugPolys.begin_drawflag = drawflag;
2526 debugPolys.begin_vertices = 0;
2527 debugPolys.begin_active = true;
2530 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2532 if(!debugPolys.begin_active)
2534 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2538 if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS)
2540 Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2544 debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x;
2545 debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y;
2546 debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z;
2547 debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s;
2548 debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t;
2549 debugPolys.begin_color[debugPolys.begin_vertices][0] = r;
2550 debugPolys.begin_color[debugPolys.begin_vertices][1] = g;
2551 debugPolys.begin_color[debugPolys.begin_vertices][2] = b;
2552 debugPolys.begin_color[debugPolys.begin_vertices][3] = a;
2553 debugPolys.begin_vertices++;
2556 void Debug_PolygonEnd(void)
2558 if (!debugPolys.begin_active)
2560 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2563 debugPolys.begin_active = false;
2564 if (debugPolys.begin_vertices >= 3)
2565 VMPolygons_Store(&debugPolys);
2567 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
2574 Returns false if any part of the bottom of the entity is off an edge that
2579 qboolean CL_CheckBottom (prvm_edict_t *ent)
2581 vec3_t mins, maxs, start, stop;
2586 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2587 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2589 // if all of the points under the corners are solid world, don't bother
2590 // with the tougher checks
2591 // the corners must be within 16 of the midpoint
2592 start[2] = mins[2] - 1;
2593 for (x=0 ; x<=1 ; x++)
2594 for (y=0 ; y<=1 ; y++)
2596 start[0] = x ? maxs[0] : mins[0];
2597 start[1] = y ? maxs[1] : mins[1];
2598 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2602 return true; // we got out easy
2606 // check it for real...
2610 // the midpoint must be within 16 of the bottom
2611 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2612 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2613 stop[2] = start[2] - 2*sv_stepheight.value;
2614 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2616 if (trace.fraction == 1.0)
2618 mid = bottom = trace.endpos[2];
2620 // the corners must be within 16 of the midpoint
2621 for (x=0 ; x<=1 ; x++)
2622 for (y=0 ; y<=1 ; y++)
2624 start[0] = stop[0] = x ? maxs[0] : mins[0];
2625 start[1] = stop[1] = y ? maxs[1] : mins[1];
2627 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2629 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2630 bottom = trace.endpos[2];
2631 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2642 Called by monster program code.
2643 The move will be adjusted for slopes and stairs, but if the move isn't
2644 possible, no move is done and false is returned
2647 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2650 vec3_t oldorg, neworg, end, traceendpos;
2653 prvm_edict_t *enemy;
2657 VectorCopy (ent->fields.client->origin, oldorg);
2658 VectorAdd (ent->fields.client->origin, move, neworg);
2660 // flying monsters don't step up
2661 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2663 // try one move with vertical motion, then one without
2664 for (i=0 ; i<2 ; i++)
2666 VectorAdd (ent->fields.client->origin, move, neworg);
2667 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2668 if (i == 0 && enemy != prog->edicts)
2670 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2676 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);
2678 VM_SetTraceGlobals(&trace);
2680 if (trace.fraction == 1)
2682 VectorCopy(trace.endpos, traceendpos);
2683 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2684 return false; // swim monster left water
2686 VectorCopy (traceendpos, ent->fields.client->origin);
2692 if (enemy == prog->edicts)
2699 // push down from a step height above the wished position
2700 neworg[2] += sv_stepheight.value;
2701 VectorCopy (neworg, end);
2702 end[2] -= sv_stepheight.value*2;
2704 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2706 VM_SetTraceGlobals(&trace);
2708 if (trace.startsolid)
2710 neworg[2] -= sv_stepheight.value;
2711 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2713 VM_SetTraceGlobals(&trace);
2714 if (trace.startsolid)
2717 if (trace.fraction == 1)
2719 // if monster had the ground pulled out, go ahead and fall
2720 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2722 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2725 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2729 return false; // walked off an edge
2732 // check point traces down for dangling corners
2733 VectorCopy (trace.endpos, ent->fields.client->origin);
2735 if (!CL_CheckBottom (ent))
2737 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2738 { // entity had floor mostly pulled out from underneath it
2739 // and is trying to correct
2744 VectorCopy (oldorg, ent->fields.client->origin);
2748 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2749 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2751 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2752 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2764 float(float yaw, float dist[, settrace]) walkmove
2767 static void VM_CL_walkmove (void)
2776 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2778 // assume failure if it returns early
2779 PRVM_G_FLOAT(OFS_RETURN) = 0;
2781 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2782 if (ent == prog->edicts)
2784 VM_Warning("walkmove: can not modify world entity\n");
2787 if (ent->priv.server->free)
2789 VM_Warning("walkmove: can not modify free entity\n");
2792 yaw = PRVM_G_FLOAT(OFS_PARM0);
2793 dist = PRVM_G_FLOAT(OFS_PARM1);
2794 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2796 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2799 yaw = yaw*M_PI*2 / 360;
2801 move[0] = cos(yaw)*dist;
2802 move[1] = sin(yaw)*dist;
2805 // save program state, because CL_movestep may call other progs
2806 oldf = prog->xfunction;
2807 oldself = prog->globals.client->self;
2809 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2812 // restore program state
2813 prog->xfunction = oldf;
2814 prog->globals.client->self = oldself;
2821 string(string key) serverkey
2824 void VM_CL_serverkey(void)
2826 char string[VM_STRINGTEMP_LENGTH];
2827 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2828 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2829 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2832 //============================================================================
2834 // To create a almost working builtin file from this replace:
2835 // "^NULL.*" with ""
2836 // "^{.*//.*}:Wh\(.*\)" with "\1"
2838 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
2839 // "\n\n+" with "\n\n"
2841 prvm_builtin_t vm_cl_builtins[] = {
2842 NULL, // #0 NULL function (not callable) (QUAKE)
2843 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2844 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2845 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2846 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2847 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2848 VM_break, // #6 void() break (QUAKE)
2849 VM_random, // #7 float() random (QUAKE)
2850 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2851 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2852 VM_error, // #10 void(string e) error (QUAKE)
2853 VM_objerror, // #11 void(string e) objerror (QUAKE)
2854 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2855 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2856 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2857 VM_remove, // #15 void(entity e) remove (QUAKE)
2858 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
2859 NULL, // #17 entity() checkclient (QUAKE)
2860 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2861 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2862 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2863 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2864 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2865 NULL, // #23 void(string s, ...) bprint (QUAKE)
2866 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2867 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2868 VM_ftos, // #26 string(float f) ftos (QUAKE)
2869 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2870 VM_coredump, // #28 void() coredump (QUAKE)
2871 VM_traceon, // #29 void() traceon (QUAKE)
2872 VM_traceoff, // #30 void() traceoff (QUAKE)
2873 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2874 VM_CL_walkmove, // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
2875 NULL, // #33 (QUAKE)
2876 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2877 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2878 VM_rint, // #36 float(float v) rint (QUAKE)
2879 VM_floor, // #37 float(float v) floor (QUAKE)
2880 VM_ceil, // #38 float(float v) ceil (QUAKE)
2881 NULL, // #39 (QUAKE)
2882 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2883 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2884 NULL, // #42 (QUAKE)
2885 VM_fabs, // #43 float(float f) fabs (QUAKE)
2886 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2887 VM_cvar, // #45 float(string s) cvar (QUAKE)
2888 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2889 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2890 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2891 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2892 NULL, // #50 (QUAKE)
2893 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2894 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2895 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2896 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2897 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2898 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2899 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2900 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2901 NULL, // #59 (QUAKE)
2902 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2903 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2904 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2905 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2906 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2907 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2908 NULL, // #66 (QUAKE)
2909 NULL, // #67 void(float step) movetogoal (QUAKE)
2910 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2911 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2912 NULL, // #70 void(string s) changelevel (QUAKE)
2913 NULL, // #71 (QUAKE)
2914 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2915 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2916 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2917 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2918 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2919 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2920 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2921 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2922 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2923 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2924 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2925 NULL, // #83 (QUAKE)
2926 NULL, // #84 (QUAKE)
2927 NULL, // #85 (QUAKE)
2928 NULL, // #86 (QUAKE)
2929 NULL, // #87 (QUAKE)
2930 NULL, // #88 (QUAKE)
2931 NULL, // #89 (QUAKE)
2932 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2933 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2934 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2935 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2936 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2937 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2938 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2939 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2940 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2941 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2942 // FrikaC and Telejano range #100-#199
2953 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2954 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2955 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2956 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2957 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2958 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2959 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2960 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2961 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2962 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3043 // FTEQW range #200-#299
3062 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3065 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3066 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3067 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3068 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3069 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3070 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3071 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3072 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3073 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3074 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3076 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3144 // CSQC range #300-#399
3145 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
3146 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3147 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3148 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3149 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3150 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3151 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3152 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3153 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3154 NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
3155 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3156 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3160 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3161 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3162 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3163 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3164 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3165 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3166 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3167 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3168 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3169 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3170 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3171 VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3172 NULL, // #327 // FIXME add stringwidth() here?
3173 NULL, // #328 // FIXME add drawsubpic() here?
3175 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3176 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3177 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3178 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3179 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3180 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3181 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3182 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3183 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3184 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3185 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3186 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3187 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3188 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3189 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3190 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3191 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscale (EXT_CSQC)
3192 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3193 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3194 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3195 VM_isserver, // #350 float() isserver (EXT_CSQC)
3196 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3197 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3198 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3199 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3205 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3206 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3207 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3208 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3209 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3210 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3211 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3212 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3245 // LordHavoc's range #400-#499
3246 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3247 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3248 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3249 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3250 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3251 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3252 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3253 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3254 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)
3255 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3256 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3257 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3258 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3259 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3260 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3261 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3262 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3263 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3264 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3265 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3266 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3267 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3268 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3269 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3270 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3271 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3272 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3273 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3274 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3275 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3276 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3277 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3278 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3279 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3280 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3281 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3282 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3283 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3284 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3285 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3286 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3287 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3288 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3289 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3290 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3291 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3292 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3293 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3294 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3295 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3296 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3297 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3298 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3299 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3300 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3301 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3302 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3303 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
3305 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3306 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3307 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3308 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3309 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3310 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3311 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3312 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3313 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3314 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3315 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3316 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3317 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3318 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3319 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3320 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3321 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3322 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3323 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3324 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3325 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3326 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3327 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3328 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3329 VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
3330 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3331 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3332 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
3333 VM_gecko_create, // #487 float gecko_create( string name )
3334 VM_gecko_destroy, // #488 void gecko_destroy( string name )
3335 VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI )
3336 VM_gecko_keyevent, // #490 float gecko_keyevent( string name, float key, float eventtype )
3337 VM_gecko_movemouse, // #491 void gecko_mousemove( string name, float x, float y )
3338 VM_gecko_resize, // #492 void gecko_resize( string name, float w, float h )
3339 VM_gecko_get_texture_extent, // #493 vector gecko_get_texture_extent( string name )
3340 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3348 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3350 void VM_Polygons_Reset(void)
3352 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
3354 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3355 if(polys->initialized)
3357 Mem_FreePool(&polys->pool);
3358 polys->initialized = false;
3362 void VM_CL_Cmd_Init(void)
3365 VM_Polygons_Reset();
3368 void VM_CL_Cmd_Reset(void)
3371 VM_Polygons_Reset();