added gl_gecko.[ch] and gl_dyntexture.[ch] dependencies
[divverent/darkplaces.git] / clvm_cmds.c
1 #include "quakedef.h"
2
3 #include "prvm_cmds.h"
4 #include "csprogs.h"
5 #include "cl_collision.h"
6 #include "r_shadow.h"
7
8 //============================================================================
9 // Client
10 //[515]: unsolved PROBLEMS
11 //- finish player physics code (cs_runplayerphysics)
12 //- EntWasFreed ?
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
17
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
20
21 sfx_t *S_FindName(const char *name);
22 int Sbar_GetSortedPlayerIndex (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);
28
29 // #1 void(vector ang) makevectors
30 static void VM_CL_makevectors (void)
31 {
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);
34 }
35
36 // #2 void(entity e, vector o) setorigin
37 void VM_CL_setorigin (void)
38 {
39         prvm_edict_t    *e;
40         float   *org;
41         VM_SAFEPARMCOUNT(2, VM_CL_setorigin);
42
43         e = PRVM_G_EDICT(OFS_PARM0);
44         if (e == prog->edicts)
45         {
46                 VM_Warning("setorigin: can not modify world entity\n");
47                 return;
48         }
49         if (e->priv.required->free)
50         {
51                 VM_Warning("setorigin: can not modify free entity\n");
52                 return;
53         }
54         org = PRVM_G_VECTOR(OFS_PARM1);
55         VectorCopy (org, e->fields.client->origin);
56         CL_LinkEdict(e);
57 }
58
59 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max)
60 {
61         int             i;
62
63         for (i=0 ; i<3 ; i++)
64                 if (min[i] > max[i])
65                         PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
66
67         // set derived values
68         VectorCopy (min, e->fields.client->mins);
69         VectorCopy (max, e->fields.client->maxs);
70         VectorSubtract (max, min, e->fields.client->size);
71
72         CL_LinkEdict (e);
73 }
74
75 // #3 void(entity e, string m) setmodel
76 void VM_CL_setmodel (void)
77 {
78         prvm_edict_t    *e;
79         const char              *m;
80         dp_model_t *mod;
81         int                             i;
82
83         VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
84
85         e = PRVM_G_EDICT(OFS_PARM0);
86         e->fields.client->modelindex = 0;
87         e->fields.client->model = 0;
88
89         m = PRVM_G_STRING(OFS_PARM1);
90         mod = NULL;
91         for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
92         {
93                 if (!strcmp(cl.csqc_model_precache[i]->name, m))
94                 {
95                         mod = cl.csqc_model_precache[i];
96                         e->fields.client->model = PRVM_SetEngineString(mod->name);
97                         e->fields.client->modelindex = -(i+1);
98                         break;
99                 }
100         }
101
102         if( !mod ) {
103                 for (i = 0;i < MAX_MODELS;i++)
104                 {
105                         mod = cl.model_precache[i];
106                         if (mod && !strcmp(mod->name, m))
107                         {
108                                 e->fields.client->model = PRVM_SetEngineString(mod->name);
109                                 e->fields.client->modelindex = i;
110                                 break;
111                         }
112                 }
113         }
114
115         if( mod ) {
116                 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
117                 //SetMinMaxSize (e, mod->normalmins, mod->normalmaxs);
118         }
119         else
120         {
121                 SetMinMaxSize (e, vec3_origin, vec3_origin);
122                 VM_Warning ("setmodel: model '%s' not precached\n", m);
123         }
124 }
125
126 // #4 void(entity e, vector min, vector max) setsize
127 static void VM_CL_setsize (void)
128 {
129         prvm_edict_t    *e;
130         float                   *min, *max;
131         VM_SAFEPARMCOUNT(3, VM_CL_setsize);
132
133         e = PRVM_G_EDICT(OFS_PARM0);
134         if (e == prog->edicts)
135         {
136                 VM_Warning("setsize: can not modify world entity\n");
137                 return;
138         }
139         if (e->priv.server->free)
140         {
141                 VM_Warning("setsize: can not modify free entity\n");
142                 return;
143         }
144         min = PRVM_G_VECTOR(OFS_PARM1);
145         max = PRVM_G_VECTOR(OFS_PARM2);
146
147         SetMinMaxSize( e, min, max );
148
149         CL_LinkEdict(e);
150 }
151
152 // #8 void(entity e, float chan, string samp, float volume, float atten) sound
153 static void VM_CL_sound (void)
154 {
155         const char                      *sample;
156         int                                     channel;
157         prvm_edict_t            *entity;
158         float                           volume;
159         float                           attenuation;
160
161         VM_SAFEPARMCOUNT(5, VM_CL_sound);
162
163         entity = PRVM_G_EDICT(OFS_PARM0);
164         channel = (int)PRVM_G_FLOAT(OFS_PARM1);
165         sample = PRVM_G_STRING(OFS_PARM2);
166         volume = PRVM_G_FLOAT(OFS_PARM3);
167         attenuation = PRVM_G_FLOAT(OFS_PARM4);
168
169         if (volume < 0 || volume > 1)
170         {
171                 VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
172                 return;
173         }
174
175         if (attenuation < 0 || attenuation > 4)
176         {
177                 VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
178                 return;
179         }
180
181         if (channel < 0 || channel > 7)
182         {
183                 VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
184                 return;
185         }
186
187         S_StartSound(32768 + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), entity->fields.client->origin, volume, attenuation);
188 }
189
190 // #483 void(vector origin, string sample, float volume, float attenuation) pointsound
191 static void VM_CL_pointsound(void)
192 {
193         const char                      *sample;
194         float                           volume;
195         float                           attenuation;
196         vec3_t                          org;
197
198         VM_SAFEPARMCOUNT(4, VM_CL_pointsound);
199
200         VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org);
201         sample = PRVM_G_STRING(OFS_PARM1);
202         volume = PRVM_G_FLOAT(OFS_PARM2);
203         attenuation = PRVM_G_FLOAT(OFS_PARM3);
204
205         if (volume < 0 || volume > 1)
206         {
207                 VM_Warning("VM_CL_pointsound: volume must be in range 0-1\n");
208                 return;
209         }
210
211         if (attenuation < 0 || attenuation > 4)
212         {
213                 VM_Warning("VM_CL_pointsound: attenuation must be in range 0-4\n");
214                 return;
215         }
216
217         // Send World Entity as Entity to Play Sound (for CSQC, that is 32768)
218         S_StartSound(32768, 0, S_FindName(sample), org, volume, attenuation);
219 }
220
221 // #14 entity() spawn
222 static void VM_CL_spawn (void)
223 {
224         prvm_edict_t *ed;
225         ed = PRVM_ED_Alloc();
226         VM_RETURN_EDICT(ed);
227 }
228
229 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
230 static void VM_CL_traceline (void)
231 {
232         float   *v1, *v2;
233         trace_t trace;
234         int             move;
235         prvm_edict_t    *ent;
236
237         VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
238
239         prog->xfunction->builtinsprofile += 30;
240
241         v1 = PRVM_G_VECTOR(OFS_PARM0);
242         v2 = PRVM_G_VECTOR(OFS_PARM1);
243         move = (int)PRVM_G_FLOAT(OFS_PARM2);
244         ent = PRVM_G_EDICT(OFS_PARM3);
245
246         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]))
247                 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));
248
249         trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
250
251         VM_SetTraceGlobals(&trace);
252 }
253
254 /*
255 =================
256 VM_CL_tracebox
257
258 Used for use tracing and shot targeting
259 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
260 if the tryents flag is set.
261
262 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
263 =================
264 */
265 // LordHavoc: added this for my own use, VERY useful, similar to traceline
266 static void VM_CL_tracebox (void)
267 {
268         float   *v1, *v2, *m1, *m2;
269         trace_t trace;
270         int             move;
271         prvm_edict_t    *ent;
272
273         VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
274
275         prog->xfunction->builtinsprofile += 30;
276
277         v1 = PRVM_G_VECTOR(OFS_PARM0);
278         m1 = PRVM_G_VECTOR(OFS_PARM1);
279         m2 = PRVM_G_VECTOR(OFS_PARM2);
280         v2 = PRVM_G_VECTOR(OFS_PARM3);
281         move = (int)PRVM_G_FLOAT(OFS_PARM4);
282         ent = PRVM_G_EDICT(OFS_PARM5);
283
284         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]))
285                 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));
286
287         trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
288
289         VM_SetTraceGlobals(&trace);
290 }
291
292 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
293 {
294         int i;
295         float gravity;
296         vec3_t move, end;
297         vec3_t original_origin;
298         vec3_t original_velocity;
299         vec3_t original_angles;
300         vec3_t original_avelocity;
301         prvm_eval_t *val;
302         trace_t trace;
303
304         VectorCopy(tossent->fields.client->origin   , original_origin   );
305         VectorCopy(tossent->fields.client->velocity , original_velocity );
306         VectorCopy(tossent->fields.client->angles   , original_angles   );
307         VectorCopy(tossent->fields.client->avelocity, original_avelocity);
308
309         val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
310         if (val != NULL && val->_float != 0)
311                 gravity = val->_float;
312         else
313                 gravity = 1.0;
314         gravity *= cl.movevars_gravity * 0.05;
315
316         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
317         {
318                 tossent->fields.client->velocity[2] -= gravity;
319                 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
320                 VectorScale (tossent->fields.client->velocity, 0.05, move);
321                 VectorAdd (tossent->fields.client->origin, move, end);
322                 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);
323                 VectorCopy (trace.endpos, tossent->fields.client->origin);
324
325                 if (trace.fraction < 1)
326                         break;
327         }
328
329         VectorCopy(original_origin   , tossent->fields.client->origin   );
330         VectorCopy(original_velocity , tossent->fields.client->velocity );
331         VectorCopy(original_angles   , tossent->fields.client->angles   );
332         VectorCopy(original_avelocity, tossent->fields.client->avelocity);
333
334         return trace;
335 }
336
337 static void VM_CL_tracetoss (void)
338 {
339         trace_t trace;
340         prvm_edict_t    *ent;
341         prvm_edict_t    *ignore;
342
343         prog->xfunction->builtinsprofile += 600;
344
345         VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
346
347         ent = PRVM_G_EDICT(OFS_PARM0);
348         if (ent == prog->edicts)
349         {
350                 VM_Warning("tracetoss: can not use world entity\n");
351                 return;
352         }
353         ignore = PRVM_G_EDICT(OFS_PARM1);
354
355         trace = CL_Trace_Toss (ent, ignore);
356
357         VM_SetTraceGlobals(&trace);
358 }
359
360
361 // #20 void(string s) precache_model
362 void VM_CL_precache_model (void)
363 {
364         const char      *name;
365         int                     i;
366         dp_model_t              *m;
367
368         VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
369
370         name = PRVM_G_STRING(OFS_PARM0);
371         for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
372         {
373                 if(!strcmp(cl.csqc_model_precache[i]->name, name))
374                 {
375                         PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
376                         return;
377                 }
378         }
379         PRVM_G_FLOAT(OFS_RETURN) = 0;
380         m = Mod_ForName(name, false, false, false);
381         if(m && m->loaded)
382         {
383                 for (i = 0;i < MAX_MODELS;i++)
384                 {
385                         if (!cl.csqc_model_precache[i])
386                         {
387                                 cl.csqc_model_precache[i] = (dp_model_t*)m;
388                                 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
389                                 return;
390                         }
391                 }
392                 VM_Warning("VM_CL_precache_model: no free models\n");
393                 return;
394         }
395         VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
396 }
397
398 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
399 {
400         prvm_edict_t    *ent;
401         int                             i, k;
402
403         ent = PRVM_NEXT_EDICT(prog->edicts);
404         for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
405         {
406                 if (ent->priv.required->free)
407                         continue;
408                 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
409                         list[k++] = ent;
410         }
411         return k;
412 }
413
414 // #22 entity(vector org, float rad) findradius
415 static void VM_CL_findradius (void)
416 {
417         prvm_edict_t    *ent, *chain;
418         vec_t                   radius, radius2;
419         vec3_t                  org, eorg, mins, maxs;
420         int                             i, numtouchedicts;
421         prvm_edict_t    *touchedicts[MAX_EDICTS];
422
423         VM_SAFEPARMCOUNT(2, VM_CL_findradius);
424
425         chain = (prvm_edict_t *)prog->edicts;
426
427         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
428         radius = PRVM_G_FLOAT(OFS_PARM1);
429         radius2 = radius * radius;
430
431         mins[0] = org[0] - (radius + 1);
432         mins[1] = org[1] - (radius + 1);
433         mins[2] = org[2] - (radius + 1);
434         maxs[0] = org[0] + (radius + 1);
435         maxs[1] = org[1] + (radius + 1);
436         maxs[2] = org[2] + (radius + 1);
437         numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
438         if (numtouchedicts > MAX_EDICTS)
439         {
440                 // this never happens   //[515]: for what then ?
441                 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
442                 numtouchedicts = MAX_EDICTS;
443         }
444         for (i = 0;i < numtouchedicts;i++)
445         {
446                 ent = touchedicts[i];
447                 // Quake did not return non-solid entities but darkplaces does
448                 // (note: this is the reason you can't blow up fallen zombies)
449                 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
450                         continue;
451                 // LordHavoc: compare against bounding box rather than center so it
452                 // doesn't miss large objects, and use DotProduct instead of Length
453                 // for a major speedup
454                 VectorSubtract(org, ent->fields.client->origin, eorg);
455                 if (sv_gameplayfix_findradiusdistancetobox.integer)
456                 {
457                         eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
458                         eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
459                         eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
460                 }
461                 else
462                         VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
463                 if (DotProduct(eorg, eorg) < radius2)
464                 {
465                         ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
466                         chain = ent;
467                 }
468         }
469
470         VM_RETURN_EDICT(chain);
471 }
472
473 // #34 float() droptofloor
474 static void VM_CL_droptofloor (void)
475 {
476         prvm_edict_t            *ent;
477         prvm_eval_t                     *val;
478         vec3_t                          end;
479         trace_t                         trace;
480
481         VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
482
483         // assume failure if it returns early
484         PRVM_G_FLOAT(OFS_RETURN) = 0;
485
486         ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
487         if (ent == prog->edicts)
488         {
489                 VM_Warning("droptofloor: can not modify world entity\n");
490                 return;
491         }
492         if (ent->priv.server->free)
493         {
494                 VM_Warning("droptofloor: can not modify free entity\n");
495                 return;
496         }
497
498         VectorCopy (ent->fields.client->origin, end);
499         end[2] -= 256;
500
501         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);
502
503         if (trace.fraction != 1)
504         {
505                 VectorCopy (trace.endpos, ent->fields.client->origin);
506                 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
507                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
508                         val->edict = PRVM_EDICT_TO_PROG(trace.ent);
509                 PRVM_G_FLOAT(OFS_RETURN) = 1;
510                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
511 //              ent->priv.server->suspendedinairflag = true;
512         }
513 }
514
515 // #35 void(float style, string value) lightstyle
516 static void VM_CL_lightstyle (void)
517 {
518         int                     i;
519         const char      *c;
520
521         VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
522
523         i = (int)PRVM_G_FLOAT(OFS_PARM0);
524         c = PRVM_G_STRING(OFS_PARM1);
525         if (i >= cl.max_lightstyle)
526         {
527                 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
528                 return;
529         }
530         strlcpy (cl.lightstyle[i].map,  MSG_ReadString(), sizeof (cl.lightstyle[i].map));
531         cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
532         cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
533 }
534
535 // #40 float(entity e) checkbottom
536 static void VM_CL_checkbottom (void)
537 {
538         static int              cs_yes, cs_no;
539         prvm_edict_t    *ent;
540         vec3_t                  mins, maxs, start, stop;
541         trace_t                 trace;
542         int                             x, y;
543         float                   mid, bottom;
544
545         VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
546         ent = PRVM_G_EDICT(OFS_PARM0);
547         PRVM_G_FLOAT(OFS_RETURN) = 0;
548
549         VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
550         VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
551
552 // if all of the points under the corners are solid world, don't bother
553 // with the tougher checks
554 // the corners must be within 16 of the midpoint
555         start[2] = mins[2] - 1;
556         for     (x=0 ; x<=1 ; x++)
557                 for     (y=0 ; y<=1 ; y++)
558                 {
559                         start[0] = x ? maxs[0] : mins[0];
560                         start[1] = y ? maxs[1] : mins[1];
561                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
562                                 goto realcheck;
563                 }
564
565         cs_yes++;
566         PRVM_G_FLOAT(OFS_RETURN) = true;
567         return;         // we got out easy
568
569 realcheck:
570         cs_no++;
571 //
572 // check it for real...
573 //
574         start[2] = mins[2];
575
576 // the midpoint must be within 16 of the bottom
577         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
578         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
579         stop[2] = start[2] - 2*sv_stepheight.value;
580         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
581
582         if (trace.fraction == 1.0)
583                 return;
584
585         mid = bottom = trace.endpos[2];
586
587 // the corners must be within 16 of the midpoint
588         for     (x=0 ; x<=1 ; x++)
589                 for     (y=0 ; y<=1 ; y++)
590                 {
591                         start[0] = stop[0] = x ? maxs[0] : mins[0];
592                         start[1] = stop[1] = y ? maxs[1] : mins[1];
593
594                         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
595
596                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
597                                 bottom = trace.endpos[2];
598                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
599                                 return;
600                 }
601
602         cs_yes++;
603         PRVM_G_FLOAT(OFS_RETURN) = true;
604 }
605
606 // #41 float(vector v) pointcontents
607 static void VM_CL_pointcontents (void)
608 {
609         VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
610         PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
611 }
612
613 // #48 void(vector o, vector d, float color, float count) particle
614 static void VM_CL_particle (void)
615 {
616         float   *org, *dir;
617         int             count;
618         unsigned char   color;
619         VM_SAFEPARMCOUNT(4, VM_CL_particle);
620
621         org = PRVM_G_VECTOR(OFS_PARM0);
622         dir = PRVM_G_VECTOR(OFS_PARM1);
623         color = (int)PRVM_G_FLOAT(OFS_PARM2);
624         count = (int)PRVM_G_FLOAT(OFS_PARM3);
625         CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
626 }
627
628 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
629 static void VM_CL_ambientsound (void)
630 {
631         float   *f;
632         sfx_t   *s;
633         VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
634         s = S_FindName(PRVM_G_STRING(OFS_PARM0));
635         f = PRVM_G_VECTOR(OFS_PARM1);
636         S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
637 }
638
639 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
640 static void VM_CL_getlight (void)
641 {
642         vec3_t ambientcolor, diffusecolor, diffusenormal;
643         vec_t *p;
644
645         VM_SAFEPARMCOUNT(1, VM_CL_getlight);
646
647         p = PRVM_G_VECTOR(OFS_PARM0);
648         VectorClear(ambientcolor);
649         VectorClear(diffusecolor);
650         VectorClear(diffusenormal);
651         if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
652                 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
653         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
654 }
655
656
657 //============================================================================
658 //[515]: SCENE MANAGER builtins
659 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
660
661 static void CSQC_R_RecalcView (void)
662 {
663         extern matrix4x4_t viewmodelmatrix;
664         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);
665         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);
666 }
667
668 void CL_RelinkLightFlashes(void);
669 //#300 void() clearscene (EXT_CSQC)
670 void VM_CL_R_ClearScene (void)
671 {
672         VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
673         // clear renderable entity and light lists
674         r_refdef.scene.numentities = 0;
675         r_refdef.scene.numlights = 0;
676         // FIXME: restore these to the values from VM_CL_UpdateView
677         r_refdef.view.x = 0;
678         r_refdef.view.y = 0;
679         r_refdef.view.z = 0;
680         r_refdef.view.width = vid.width;
681         r_refdef.view.height = vid.height;
682         r_refdef.view.depth = 1;
683         // FIXME: restore frustum_x/frustum_y
684         r_refdef.view.useperspective = true;
685         r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
686         r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
687         r_refdef.view.frustum_x *= r_refdef.frustumscale_x;
688         r_refdef.view.frustum_y *= r_refdef.frustumscale_y;
689         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;
690         r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
691         r_refdef.view.clear = true;
692         r_refdef.view.isoverlay = false;
693         // FIXME: restore cl.csqc_origin
694         // FIXME: restore cl.csqc_angles
695         cl.csqc_vidvars.drawworld = true;
696         cl.csqc_vidvars.drawenginesbar = false;
697         cl.csqc_vidvars.drawcrosshair = false;
698 }
699
700 //#301 void(float mask) addentities (EXT_CSQC)
701 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
702 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
703 void VM_CL_R_AddEntities (void)
704 {
705         int                     i, drawmask;
706         prvm_edict_t *ed;
707         VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
708         drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
709         CSQC_RelinkAllEntities(drawmask);
710         CL_RelinkLightFlashes();
711
712         prog->globals.client->time = cl.time;
713         for(i=1;i<prog->num_edicts;i++)
714         {
715                 ed = &prog->edicts[i];
716                 if(ed->priv.required->free)
717                         continue;
718                 CSQC_Think(ed);
719                 if(ed->priv.required->free)
720                         continue;
721                 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
722                 CSQC_Predraw(ed);
723                 if(ed->priv.required->free)
724                         continue;
725                 if(!((int)ed->fields.client->drawmask & drawmask))
726                         continue;
727                 CSQC_AddRenderEdict(ed);
728         }
729 }
730
731 //#302 void(entity ent) addentity (EXT_CSQC)
732 void VM_CL_R_AddEntity (void)
733 {
734         VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
735         CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
736 }
737
738 //#303 float(float property, ...) setproperty (EXT_CSQC)
739 void VM_CL_R_SetView (void)
740 {
741         int             c;
742         float   *f;
743         float   k;
744
745         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
746
747         c = (int)PRVM_G_FLOAT(OFS_PARM0);
748         f = PRVM_G_VECTOR(OFS_PARM1);
749         k = PRVM_G_FLOAT(OFS_PARM1);
750
751         switch(c)
752         {
753         case VF_MIN:
754                 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
755                 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
756                 break;
757         case VF_MIN_X:
758                 r_refdef.view.x = (int)(k * vid.width / vid_conwidth.value);
759                 break;
760         case VF_MIN_Y:
761                 r_refdef.view.y = (int)(k * vid.height / vid_conheight.value);
762                 break;
763         case VF_SIZE:
764                 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
765                 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
766                 break;
767         case VF_SIZE_X:
768                 r_refdef.view.width = (int)(k * vid.width / vid_conwidth.value);
769                 break;
770         case VF_SIZE_Y:
771                 r_refdef.view.height = (int)(k * vid.height / vid_conheight.value);
772                 break;
773         case VF_VIEWPORT:
774                 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
775                 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
776                 f = PRVM_G_VECTOR(OFS_PARM2);
777                 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
778                 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
779                 break;
780         case VF_FOV:
781                 r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
782                 r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
783                 break;
784         case VF_FOVX:
785                 r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
786                 break;
787         case VF_FOVY:
788                 r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
789                 break;
790         case VF_ORIGIN:
791                 VectorCopy(f, cl.csqc_origin);
792                 CSQC_R_RecalcView();
793                 break;
794         case VF_ORIGIN_X:
795                 cl.csqc_origin[0] = k;
796                 CSQC_R_RecalcView();
797                 break;
798         case VF_ORIGIN_Y:
799                 cl.csqc_origin[1] = k;
800                 CSQC_R_RecalcView();
801                 break;
802         case VF_ORIGIN_Z:
803                 cl.csqc_origin[2] = k;
804                 CSQC_R_RecalcView();
805                 break;
806         case VF_ANGLES:
807                 VectorCopy(f, cl.csqc_angles);
808                 CSQC_R_RecalcView();
809                 break;
810         case VF_ANGLES_X:
811                 cl.csqc_angles[0] = k;
812                 CSQC_R_RecalcView();
813                 break;
814         case VF_ANGLES_Y:
815                 cl.csqc_angles[1] = k;
816                 CSQC_R_RecalcView();
817                 break;
818         case VF_ANGLES_Z:
819                 cl.csqc_angles[2] = k;
820                 CSQC_R_RecalcView();
821                 break;
822         case VF_DRAWWORLD:
823                 cl.csqc_vidvars.drawworld = k;
824                 break;
825         case VF_DRAWENGINESBAR:
826                 cl.csqc_vidvars.drawenginesbar = k;
827                 break;
828         case VF_DRAWCROSSHAIR:
829                 cl.csqc_vidvars.drawcrosshair = k;
830                 break;
831         case VF_CL_VIEWANGLES:
832                 VectorCopy(f, cl.viewangles);
833                 break;
834         case VF_CL_VIEWANGLES_X:
835                 cl.viewangles[0] = k;
836                 break;
837         case VF_CL_VIEWANGLES_Y:
838                 cl.viewangles[1] = k;
839                 break;
840         case VF_CL_VIEWANGLES_Z:
841                 cl.viewangles[2] = k;
842                 break;
843         case VF_PERSPECTIVE:
844                 r_refdef.view.useperspective = k != 0;
845                 break;
846         case VF_CLEARSCREEN:
847                 r_refdef.view.isoverlay = !k;
848                 break;
849         default:
850                 PRVM_G_FLOAT(OFS_RETURN) = 0;
851                 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
852                 return;
853         }
854         PRVM_G_FLOAT(OFS_RETURN) = 1;
855 }
856
857 //#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC)
858 void VM_CL_R_AddDynamicLight (void)
859 {
860         vec_t *org;
861         float radius = 300;
862         vec_t *col;
863         int style = -1;
864         const char *cubemapname = NULL;
865         int pflags = PFLAGS_CORONA | PFLAGS_FULLDYNAMIC;
866         float coronaintensity = 1;
867         float coronasizescale = 0.25;
868         qboolean castshadow = true;
869         float ambientscale = 0;
870         float diffusescale = 1;
871         float specularscale = 1;
872         matrix4x4_t matrix;
873         vec3_t forward, left, up;
874         VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight);
875
876         // if we've run out of dlights, just return
877         if (r_refdef.scene.numlights >= MAX_DLIGHTS)
878                 return;
879
880         org = PRVM_G_VECTOR(OFS_PARM0);
881         radius = PRVM_G_FLOAT(OFS_PARM1);
882         col = PRVM_G_VECTOR(OFS_PARM2);
883         if (prog->argc >= 4)
884         {
885                 style = (int)PRVM_G_FLOAT(OFS_PARM3);
886                 if (style >= MAX_LIGHTSTYLES)
887                 {
888                         Con_DPrintf("VM_CL_R_AddDynamicLight: out of bounds lightstyle index %i\n", style);
889                         style = -1;
890                 }
891         }
892         if (prog->argc >= 5)
893                 cubemapname = PRVM_G_STRING(OFS_PARM4);
894         if (prog->argc >= 6)
895                 pflags = (int)PRVM_G_FLOAT(OFS_PARM5);
896         coronaintensity = (pflags & PFLAGS_CORONA) != 0;
897         castshadow = (pflags & PFLAGS_NOSHADOW) == 0;
898
899         VectorScale(prog->globals.client->v_forward, radius, forward);
900         VectorScale(prog->globals.client->v_right, -radius, left);
901         VectorScale(prog->globals.client->v_up, radius, up);
902         Matrix4x4_FromVectors(&matrix, forward, left, up, org);
903
904         R_RTLight_Update(&r_refdef.scene.lights[r_refdef.scene.numlights++], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
905 }
906
907 //============================================================================
908
909 //#310 vector (vector v) cs_unproject (EXT_CSQC)
910 static void VM_CL_unproject (void)
911 {
912         float   *f;
913         vec3_t  temp;
914
915         VM_SAFEPARMCOUNT(1, VM_CL_unproject);
916         f = PRVM_G_VECTOR(OFS_PARM0);
917         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);
918         Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
919 }
920
921 //#311 vector (vector v) cs_project (EXT_CSQC)
922 static void VM_CL_project (void)
923 {
924         float   *f;
925         vec3_t  v;
926         matrix4x4_t m;
927
928         VM_SAFEPARMCOUNT(1, VM_CL_project);
929         f = PRVM_G_VECTOR(OFS_PARM0);
930         Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
931         Matrix4x4_Transform(&m, f, v);
932         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]);
933 }
934
935 //#330 float(float stnum) getstatf (EXT_CSQC)
936 static void VM_CL_getstatf (void)
937 {
938         int i;
939         union
940         {
941                 float f;
942                 int l;
943         }dat;
944         VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
945         i = (int)PRVM_G_FLOAT(OFS_PARM0);
946         if(i < 0 || i >= MAX_CL_STATS)
947         {
948                 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
949                 return;
950         }
951         dat.l = cl.stats[i];
952         PRVM_G_FLOAT(OFS_RETURN) =  dat.f;
953 }
954
955 //#331 float(float stnum) getstati (EXT_CSQC)
956 static void VM_CL_getstati (void)
957 {
958         int i, index;
959         int firstbit, bitcount;
960
961         VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
962
963         index = (int)PRVM_G_FLOAT(OFS_PARM0);
964         if (prog->argc > 1)
965         {
966                 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
967                 if (prog->argc > 2)
968                         bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
969                 else
970                         bitcount = 1;
971         }
972         else
973         {
974                 firstbit = 0;
975                 bitcount = 32;
976         }
977
978         if(index < 0 || index >= MAX_CL_STATS)
979         {
980                 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
981                 return;
982         }
983         i = cl.stats[index];
984         if (bitcount != 32)     //32 causes the mask to overflow, so there's nothing to subtract from.
985                 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
986         PRVM_G_FLOAT(OFS_RETURN) = i;
987 }
988
989 //#332 string(float firststnum) getstats (EXT_CSQC)
990 static void VM_CL_getstats (void)
991 {
992         int i;
993         char t[17];
994         VM_SAFEPARMCOUNT(1, VM_CL_getstats);
995         i = (int)PRVM_G_FLOAT(OFS_PARM0);
996         if(i < 0 || i > MAX_CL_STATS-4)
997         {
998                 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
999                 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
1000                 return;
1001         }
1002         strlcpy(t, (char*)&cl.stats[i], sizeof(t));
1003         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1004 }
1005
1006 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
1007 static void VM_CL_setmodelindex (void)
1008 {
1009         int                             i;
1010         prvm_edict_t    *t;
1011         struct model_s  *model;
1012
1013         VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
1014
1015         t = PRVM_G_EDICT(OFS_PARM0);
1016
1017         i = (int)PRVM_G_FLOAT(OFS_PARM1);
1018
1019         t->fields.client->model = 0;
1020         t->fields.client->modelindex = 0;
1021
1022         if (!i)
1023                 return;
1024
1025         model = CL_GetModelByIndex(i);
1026         if (!model)
1027         {
1028                 VM_Warning("VM_CL_setmodelindex: null model\n");
1029                 return;
1030         }
1031         t->fields.client->model = PRVM_SetEngineString(model->name);
1032         t->fields.client->modelindex = i;
1033
1034         // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
1035         if (model)
1036         {
1037                 SetMinMaxSize (t, model->normalmins, model->normalmaxs);
1038         }
1039         else
1040                 SetMinMaxSize (t, vec3_origin, vec3_origin);
1041 }
1042
1043 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
1044 static void VM_CL_modelnameforindex (void)
1045 {
1046         dp_model_t *model;
1047
1048         VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
1049
1050         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1051         model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
1052         PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
1053 }
1054
1055 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
1056 static void VM_CL_particleeffectnum (void)
1057 {
1058         int                     i;
1059         VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
1060         i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
1061         if (i == 0)
1062                 i = -1;
1063         PRVM_G_FLOAT(OFS_RETURN) = i;
1064 }
1065
1066 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
1067 static void VM_CL_trailparticles (void)
1068 {
1069         int                             i;
1070         float                   *start, *end;
1071         prvm_edict_t    *t;
1072         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
1073
1074         t = PRVM_G_EDICT(OFS_PARM0);
1075         i               = (int)PRVM_G_FLOAT(OFS_PARM1);
1076         start   = PRVM_G_VECTOR(OFS_PARM2);
1077         end             = PRVM_G_VECTOR(OFS_PARM3);
1078
1079         if (i < 0)
1080                 return;
1081         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);
1082 }
1083
1084 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
1085 static void VM_CL_pointparticles (void)
1086 {
1087         int                     i, n;
1088         float           *f, *v;
1089         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
1090         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1091         f = PRVM_G_VECTOR(OFS_PARM1);
1092         v = PRVM_G_VECTOR(OFS_PARM2);
1093         n = (int)PRVM_G_FLOAT(OFS_PARM3);
1094         if (i < 0)
1095                 return;
1096         CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1097 }
1098
1099 //#342 string(float keynum) getkeybind (EXT_CSQC)
1100 static void VM_CL_getkeybind (void)
1101 {
1102         VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
1103         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
1104 }
1105
1106 //#343 void(float usecursor) setcursormode (EXT_CSQC)
1107 static void VM_CL_setcursormode (void)
1108 {
1109         VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
1110         cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
1111         cl_ignoremousemoves = 2;
1112 }
1113
1114 //#344 vector() getmousepos (EXT_CSQC)
1115 static void VM_CL_getmousepos(void)
1116 {
1117         VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
1118
1119         if (key_consoleactive || key_dest != key_game)
1120                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0);
1121         else if (cl.csqc_wantsmousemove)
1122                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
1123         else
1124                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
1125 }
1126
1127 //#345 float(float framenum) getinputstate (EXT_CSQC)
1128 static void VM_CL_getinputstate (void)
1129 {
1130         int i, frame;
1131         VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1132         frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1133         for (i = 0;i < CL_MAX_USERCMDS;i++)
1134         {
1135                 if (cl.movecmd[i].sequence == frame)
1136                 {
1137                         VectorCopy(cl.movecmd[i].viewangles, prog->globals.client->input_angles);
1138                         prog->globals.client->input_buttons = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?)
1139                         prog->globals.client->input_movevalues[0] = cl.movecmd[i].forwardmove;
1140                         prog->globals.client->input_movevalues[1] = cl.movecmd[i].sidemove;
1141                         prog->globals.client->input_movevalues[2] = cl.movecmd[i].upmove;
1142                         prog->globals.client->input_timelength = cl.movecmd[i].frametime;
1143                         if(cl.movecmd[i].crouch)
1144                         {
1145                                 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1146                                 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1147                         }
1148                         else
1149                         {
1150                                 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1151                                 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1152                         }
1153                 }
1154         }
1155 }
1156
1157 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1158 static void VM_CL_setsensitivityscale (void)
1159 {
1160         VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1161         cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1162 }
1163
1164 //#347 void() runstandardplayerphysics (EXT_CSQC)
1165 static void VM_CL_runplayerphysics (void)
1166 {
1167 }
1168
1169 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1170 static void VM_CL_getplayerkey (void)
1171 {
1172         int                     i;
1173         char            t[128];
1174         const char      *c;
1175
1176         VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1177
1178         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1179         c = PRVM_G_STRING(OFS_PARM1);
1180         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1181         Sbar_SortFrags();
1182
1183         if (i < 0)
1184                 i = Sbar_GetSortedPlayerIndex(-1-i);
1185         if(i < 0 || i >= cl.maxclients)
1186                 return;
1187
1188         t[0] = 0;
1189
1190         if(!strcasecmp(c, "name"))
1191                 strlcpy(t, cl.scores[i].name, sizeof(t));
1192         else
1193                 if(!strcasecmp(c, "frags"))
1194                         sprintf(t, "%i", cl.scores[i].frags);
1195         else
1196                 if(!strcasecmp(c, "ping"))
1197                         sprintf(t, "%i", cl.scores[i].qw_ping);
1198         else
1199                 if(!strcasecmp(c, "pl"))
1200                         sprintf(t, "%i", cl.scores[i].qw_packetloss);
1201         else
1202                 if(!strcasecmp(c, "entertime"))
1203                         sprintf(t, "%f", cl.scores[i].qw_entertime);
1204         else
1205                 if(!strcasecmp(c, "colors"))
1206                         sprintf(t, "%i", cl.scores[i].colors);
1207         else
1208                 if(!strcasecmp(c, "topcolor"))
1209                         sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1210         else
1211                 if(!strcasecmp(c, "bottomcolor"))
1212                         sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1213         else
1214                 if(!strcasecmp(c, "viewentity"))
1215                         sprintf(t, "%i", i+1);
1216         if(!t[0])
1217                 return;
1218         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1219 }
1220
1221 //#349 float() isdemo (EXT_CSQC)
1222 static void VM_CL_isdemo (void)
1223 {
1224         VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1225         PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1226 }
1227
1228 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1229 static void VM_CL_setlistener (void)
1230 {
1231         VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1232         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));
1233         cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1234 }
1235
1236 //#352 void(string cmdname) registercommand (EXT_CSQC)
1237 static void VM_CL_registercmd (void)
1238 {
1239         char *t;
1240         VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1241         if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1242         {
1243                 size_t alloclen;
1244
1245                 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1246                 t = (char *)Z_Malloc(alloclen);
1247                 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1248                 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1249         }
1250         else
1251                 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1252
1253 }
1254
1255 //#360 float() readbyte (EXT_CSQC)
1256 static void VM_CL_ReadByte (void)
1257 {
1258         VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1259         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1260 }
1261
1262 //#361 float() readchar (EXT_CSQC)
1263 static void VM_CL_ReadChar (void)
1264 {
1265         VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1266         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1267 }
1268
1269 //#362 float() readshort (EXT_CSQC)
1270 static void VM_CL_ReadShort (void)
1271 {
1272         VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1273         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1274 }
1275
1276 //#363 float() readlong (EXT_CSQC)
1277 static void VM_CL_ReadLong (void)
1278 {
1279         VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1280         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1281 }
1282
1283 //#364 float() readcoord (EXT_CSQC)
1284 static void VM_CL_ReadCoord (void)
1285 {
1286         VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1287         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1288 }
1289
1290 //#365 float() readangle (EXT_CSQC)
1291 static void VM_CL_ReadAngle (void)
1292 {
1293         VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1294         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1295 }
1296
1297 //#366 string() readstring (EXT_CSQC)
1298 static void VM_CL_ReadString (void)
1299 {
1300         VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1301         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1302 }
1303
1304 //#367 float() readfloat (EXT_CSQC)
1305 static void VM_CL_ReadFloat (void)
1306 {
1307         VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1308         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1309 }
1310
1311 //////////////////////////////////////////////////////////
1312
1313 static void VM_CL_makestatic (void)
1314 {
1315         prvm_edict_t *ent;
1316
1317         VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1318
1319         ent = PRVM_G_EDICT(OFS_PARM0);
1320         if (ent == prog->edicts)
1321         {
1322                 VM_Warning("makestatic: can not modify world entity\n");
1323                 return;
1324         }
1325         if (ent->priv.server->free)
1326         {
1327                 VM_Warning("makestatic: can not modify free entity\n");
1328                 return;
1329         }
1330
1331         if (cl.num_static_entities < cl.max_static_entities)
1332         {
1333                 int renderflags;
1334                 prvm_eval_t *val;
1335                 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1336
1337                 // copy it to the current state
1338                 memset(staticent, 0, sizeof(*staticent));
1339                 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1340                 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1341                 staticent->render.framelerp = 0;
1342                 // make torchs play out of sync
1343                 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1344                 staticent->render.skinnum = (int)ent->fields.client->skin;
1345                 staticent->render.effects = (int)ent->fields.client->effects;
1346                 staticent->render.alpha = 1;
1347                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1348                 staticent->render.scale = 1;
1349                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1350                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1351
1352                 renderflags = 0;
1353                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1354                 if (renderflags & RF_USEAXIS)
1355                 {
1356                         vec3_t left;
1357                         VectorNegate(prog->globals.client->v_right, left);
1358                         Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1359                         Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1360                 }
1361                 else
1362                         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);
1363
1364                 // either fullbright or lit
1365                 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1366                         staticent->render.flags |= RENDER_LIGHT;
1367                 // turn off shadows from transparent objects
1368                 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1369                         staticent->render.flags |= RENDER_SHADOW;
1370
1371                 CL_UpdateRenderEntity(&staticent->render);
1372         }
1373         else
1374                 Con_Printf("Too many static entities");
1375
1376 // throw the entity away now
1377         PRVM_ED_Free (ent);
1378 }
1379
1380 //=================================================================//
1381
1382 /*
1383 =================
1384 VM_CL_copyentity
1385
1386 copies data from one entity to another
1387
1388 copyentity(src, dst)
1389 =================
1390 */
1391 static void VM_CL_copyentity (void)
1392 {
1393         prvm_edict_t *in, *out;
1394         VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1395         in = PRVM_G_EDICT(OFS_PARM0);
1396         if (in == prog->edicts)
1397         {
1398                 VM_Warning("copyentity: can not read world entity\n");
1399                 return;
1400         }
1401         if (in->priv.server->free)
1402         {
1403                 VM_Warning("copyentity: can not read free entity\n");
1404                 return;
1405         }
1406         out = PRVM_G_EDICT(OFS_PARM1);
1407         if (out == prog->edicts)
1408         {
1409                 VM_Warning("copyentity: can not modify world entity\n");
1410                 return;
1411         }
1412         if (out->priv.server->free)
1413         {
1414                 VM_Warning("copyentity: can not modify free entity\n");
1415                 return;
1416         }
1417         memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1418         CL_LinkEdict(out);
1419 }
1420
1421 //=================================================================//
1422
1423 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1424 static void VM_CL_effect (void)
1425 {
1426         VM_SAFEPARMCOUNT(5, VM_CL_effect);
1427         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));
1428 }
1429
1430 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1431 static void VM_CL_te_blood (void)
1432 {
1433         float   *pos;
1434         vec3_t  pos2;
1435         VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1436         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1437                 return;
1438         pos = PRVM_G_VECTOR(OFS_PARM0);
1439         CL_FindNonSolidLocation(pos, pos2, 4);
1440         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1441 }
1442
1443 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1444 static void VM_CL_te_bloodshower (void)
1445 {
1446         vec_t speed;
1447         vec3_t vel1, vel2;
1448         VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1449         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1450                 return;
1451         speed = PRVM_G_FLOAT(OFS_PARM2);
1452         vel1[0] = -speed;
1453         vel1[1] = -speed;
1454         vel1[2] = -speed;
1455         vel2[0] = speed;
1456         vel2[1] = speed;
1457         vel2[2] = speed;
1458         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1459 }
1460
1461 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1462 static void VM_CL_te_explosionrgb (void)
1463 {
1464         float           *pos;
1465         vec3_t          pos2;
1466         matrix4x4_t     tempmatrix;
1467         VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1468         pos = PRVM_G_VECTOR(OFS_PARM0);
1469         CL_FindNonSolidLocation(pos, pos2, 10);
1470         CL_ParticleExplosion(pos2);
1471         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1472         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);
1473 }
1474
1475 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1476 static void VM_CL_te_particlecube (void)
1477 {
1478         VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1479         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));
1480 }
1481
1482 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1483 static void VM_CL_te_particlerain (void)
1484 {
1485         VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1486         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);
1487 }
1488
1489 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1490 static void VM_CL_te_particlesnow (void)
1491 {
1492         VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1493         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);
1494 }
1495
1496 // #411 void(vector org, vector vel, float howmany) te_spark
1497 static void VM_CL_te_spark (void)
1498 {
1499         float           *pos;
1500         vec3_t          pos2;
1501         VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1502
1503         pos = PRVM_G_VECTOR(OFS_PARM0);
1504         CL_FindNonSolidLocation(pos, pos2, 4);
1505         CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1506 }
1507
1508 extern cvar_t cl_sound_ric_gunshot;
1509 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1510 static void VM_CL_te_gunshotquad (void)
1511 {
1512         float           *pos;
1513         vec3_t          pos2;
1514         int                     rnd;
1515         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1516
1517         pos = PRVM_G_VECTOR(OFS_PARM0);
1518         CL_FindNonSolidLocation(pos, pos2, 4);
1519         CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1520         if(cl_sound_ric_gunshot.integer >= 2)
1521         {
1522                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1523                 else
1524                 {
1525                         rnd = rand() & 3;
1526                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1527                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1528                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1529                 }
1530         }
1531 }
1532
1533 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1534 static void VM_CL_te_spikequad (void)
1535 {
1536         float           *pos;
1537         vec3_t          pos2;
1538         int                     rnd;
1539         VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1540
1541         pos = PRVM_G_VECTOR(OFS_PARM0);
1542         CL_FindNonSolidLocation(pos, pos2, 4);
1543         CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1544         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1545         else
1546         {
1547                 rnd = rand() & 3;
1548                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1549                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1550                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1551         }
1552 }
1553
1554 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1555 static void VM_CL_te_superspikequad (void)
1556 {
1557         float           *pos;
1558         vec3_t          pos2;
1559         int                     rnd;
1560         VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1561
1562         pos = PRVM_G_VECTOR(OFS_PARM0);
1563         CL_FindNonSolidLocation(pos, pos2, 4);
1564         CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1565         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1566         else
1567         {
1568                 rnd = rand() & 3;
1569                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1570                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1571                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1572         }
1573 }
1574
1575 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1576 static void VM_CL_te_explosionquad (void)
1577 {
1578         float           *pos;
1579         vec3_t          pos2;
1580         VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1581
1582         pos = PRVM_G_VECTOR(OFS_PARM0);
1583         CL_FindNonSolidLocation(pos, pos2, 10);
1584         CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1585         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1586 }
1587
1588 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1589 static void VM_CL_te_smallflash (void)
1590 {
1591         float           *pos;
1592         vec3_t          pos2;
1593         VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1594
1595         pos = PRVM_G_VECTOR(OFS_PARM0);
1596         CL_FindNonSolidLocation(pos, pos2, 10);
1597         CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1598 }
1599
1600 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1601 static void VM_CL_te_customflash (void)
1602 {
1603         float           *pos;
1604         vec3_t          pos2;
1605         matrix4x4_t     tempmatrix;
1606         VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1607
1608         pos = PRVM_G_VECTOR(OFS_PARM0);
1609         CL_FindNonSolidLocation(pos, pos2, 4);
1610         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1611         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);
1612 }
1613
1614 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1615 static void VM_CL_te_gunshot (void)
1616 {
1617         float           *pos;
1618         vec3_t          pos2;
1619         int                     rnd;
1620         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1621
1622         pos = PRVM_G_VECTOR(OFS_PARM0);
1623         CL_FindNonSolidLocation(pos, pos2, 4);
1624         CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1625         if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1626         {
1627                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1628                 else
1629                 {
1630                         rnd = rand() & 3;
1631                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1632                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1633                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1634                 }
1635         }
1636 }
1637
1638 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1639 static void VM_CL_te_spike (void)
1640 {
1641         float           *pos;
1642         vec3_t          pos2;
1643         int                     rnd;
1644         VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1645
1646         pos = PRVM_G_VECTOR(OFS_PARM0);
1647         CL_FindNonSolidLocation(pos, pos2, 4);
1648         CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1649         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1650         else
1651         {
1652                 rnd = rand() & 3;
1653                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1654                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1655                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1656         }
1657 }
1658
1659 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1660 static void VM_CL_te_superspike (void)
1661 {
1662         float           *pos;
1663         vec3_t          pos2;
1664         int                     rnd;
1665         VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1666
1667         pos = PRVM_G_VECTOR(OFS_PARM0);
1668         CL_FindNonSolidLocation(pos, pos2, 4);
1669         CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1670         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1671         else
1672         {
1673                 rnd = rand() & 3;
1674                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1675                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1676                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1677         }
1678 }
1679
1680 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1681 static void VM_CL_te_explosion (void)
1682 {
1683         float           *pos;
1684         vec3_t          pos2;
1685         VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1686
1687         pos = PRVM_G_VECTOR(OFS_PARM0);
1688         CL_FindNonSolidLocation(pos, pos2, 10);
1689         CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1690         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1691 }
1692
1693 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1694 static void VM_CL_te_tarexplosion (void)
1695 {
1696         float           *pos;
1697         vec3_t          pos2;
1698         VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1699
1700         pos = PRVM_G_VECTOR(OFS_PARM0);
1701         CL_FindNonSolidLocation(pos, pos2, 10);
1702         CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1703         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1704 }
1705
1706 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1707 static void VM_CL_te_wizspike (void)
1708 {
1709         float           *pos;
1710         vec3_t          pos2;
1711         VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1712
1713         pos = PRVM_G_VECTOR(OFS_PARM0);
1714         CL_FindNonSolidLocation(pos, pos2, 4);
1715         CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1716         S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1717 }
1718
1719 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1720 static void VM_CL_te_knightspike (void)
1721 {
1722         float           *pos;
1723         vec3_t          pos2;
1724         VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1725
1726         pos = PRVM_G_VECTOR(OFS_PARM0);
1727         CL_FindNonSolidLocation(pos, pos2, 4);
1728         CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1729         S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1730 }
1731
1732 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1733 static void VM_CL_te_lavasplash (void)
1734 {
1735         VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1736         CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1737 }
1738
1739 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1740 static void VM_CL_te_teleport (void)
1741 {
1742         VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1743         CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1744 }
1745
1746 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1747 static void VM_CL_te_explosion2 (void)
1748 {
1749         float           *pos;
1750         vec3_t          pos2, color;
1751         matrix4x4_t     tempmatrix;
1752         int                     colorStart, colorLength;
1753         unsigned char           *tempcolor;
1754         VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1755
1756         pos = PRVM_G_VECTOR(OFS_PARM0);
1757         colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1758         colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1759         CL_FindNonSolidLocation(pos, pos2, 10);
1760         CL_ParticleExplosion2(pos2, colorStart, colorLength);
1761         tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
1762         color[0] = tempcolor[0] * (2.0f / 255.0f);
1763         color[1] = tempcolor[1] * (2.0f / 255.0f);
1764         color[2] = tempcolor[2] * (2.0f / 255.0f);
1765         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1766         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);
1767         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1768 }
1769
1770
1771 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1772 static void VM_CL_te_lightning1 (void)
1773 {
1774         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1775         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1776 }
1777
1778 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1779 static void VM_CL_te_lightning2 (void)
1780 {
1781         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1782         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1783 }
1784
1785 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1786 static void VM_CL_te_lightning3 (void)
1787 {
1788         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1789         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1790 }
1791
1792 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1793 static void VM_CL_te_beam (void)
1794 {
1795         VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1796         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1797 }
1798
1799 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1800 static void VM_CL_te_plasmaburn (void)
1801 {
1802         float           *pos;
1803         vec3_t          pos2;
1804         VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1805
1806         pos = PRVM_G_VECTOR(OFS_PARM0);
1807         CL_FindNonSolidLocation(pos, pos2, 4);
1808         CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1809 }
1810
1811 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1812 static void VM_CL_te_flamejet (void)
1813 {
1814         float *pos;
1815         vec3_t pos2;
1816         VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1817         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1818                 return;
1819         pos = PRVM_G_VECTOR(OFS_PARM0);
1820         CL_FindNonSolidLocation(pos, pos2, 4);
1821         CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1822 }
1823
1824
1825 //====================================================================
1826 //DP_QC_GETSURFACE
1827
1828 extern void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1829
1830 static msurface_t *cl_getsurface(dp_model_t *model, int surfacenum)
1831 {
1832         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1833                 return NULL;
1834         return model->data_surfaces + surfacenum + model->firstmodelsurface;
1835 }
1836
1837 // #434 float(entity e, float s) getsurfacenumpoints
1838 static void VM_CL_getsurfacenumpoints(void)
1839 {
1840         dp_model_t *model;
1841         msurface_t *surface;
1842         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1843         // return 0 if no such surface
1844         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1845         {
1846                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1847                 return;
1848         }
1849
1850         // note: this (incorrectly) assumes it is a simple polygon
1851         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1852 }
1853
1854 // #435 vector(entity e, float s, float n) getsurfacepoint
1855 static void VM_CL_getsurfacepoint(void)
1856 {
1857         prvm_edict_t *ed;
1858         dp_model_t *model;
1859         msurface_t *surface;
1860         int pointnum;
1861         VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1862         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1863         ed = PRVM_G_EDICT(OFS_PARM0);
1864         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1865                 return;
1866         // note: this (incorrectly) assumes it is a simple polygon
1867         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1868         if (pointnum < 0 || pointnum >= surface->num_vertices)
1869                 return;
1870         // FIXME: implement rotation/scaling
1871         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1872 }
1873 //PF_getsurfacepointattribute,     // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
1874 // float SPA_POSITION = 0;
1875 // float SPA_S_AXIS = 1;
1876 // float SPA_T_AXIS = 2;
1877 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1878 // float SPA_TEXCOORDS0 = 4;
1879 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1880 // float SPA_LIGHTMAP0_COLOR = 6;
1881 // TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black]
1882 static void VM_CL_getsurfacepointattribute(void)
1883 {
1884         prvm_edict_t *ed;
1885         dp_model_t *model;
1886         msurface_t *surface;
1887         int pointnum;
1888         int attributetype;
1889
1890         VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints);
1891         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1892         ed = PRVM_G_EDICT(OFS_PARM0);
1893         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1894                 return;
1895         // note: this (incorrectly) assumes it is a simple polygon
1896         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1897         if (pointnum < 0 || pointnum >= surface->num_vertices)
1898                 return;
1899
1900         // FIXME: implement rotation/scaling
1901         attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
1902
1903         switch( attributetype ) {
1904                 // float SPA_POSITION = 0;
1905                 case 0:
1906                         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1907                         break;
1908                 // float SPA_S_AXIS = 1;
1909                 case 1:
1910                         VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1911                         break;
1912                 // float SPA_T_AXIS = 2;
1913                 case 2:
1914                         VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1915                         break;
1916                 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1917                 case 3:
1918                         VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1919                         break;
1920                 // float SPA_TEXCOORDS0 = 4;
1921                 case 4: {
1922                         float *ret = PRVM_G_VECTOR(OFS_RETURN);
1923                         float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
1924                         ret[0] = texcoord[0];
1925                         ret[1] = texcoord[1];
1926                         ret[2] = 0.0f;
1927                         break;
1928                 }
1929                 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1930                 case 5: {
1931                         float *ret = PRVM_G_VECTOR(OFS_RETURN);
1932                         float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
1933                         ret[0] = texcoord[0];
1934                         ret[1] = texcoord[1];
1935                         ret[2] = 0.0f;
1936                         break;
1937                 }
1938                 // float SPA_LIGHTMAP0_COLOR = 6;
1939                 case 6:
1940                         // ignore alpha for now..
1941                         VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
1942                         break;
1943                 default:
1944                         VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
1945                         break;
1946         }
1947 }
1948 // #436 vector(entity e, float s) getsurfacenormal
1949 static void VM_CL_getsurfacenormal(void)
1950 {
1951         dp_model_t *model;
1952         msurface_t *surface;
1953         vec3_t normal;
1954         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1955         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1956         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1957                 return;
1958         // FIXME: implement rotation/scaling
1959         // note: this (incorrectly) assumes it is a simple polygon
1960         // note: this only returns the first triangle, so it doesn't work very
1961         // well for curved surfaces or arbitrary meshes
1962         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);
1963         VectorNormalize(normal);
1964         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1965 }
1966
1967 // #437 string(entity e, float s) getsurfacetexture
1968 static void VM_CL_getsurfacetexture(void)
1969 {
1970         dp_model_t *model;
1971         msurface_t *surface;
1972         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1973         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1974         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1975                 return;
1976         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1977 }
1978
1979 // #438 float(entity e, vector p) getsurfacenearpoint
1980 static void VM_CL_getsurfacenearpoint(void)
1981 {
1982         int surfacenum, best;
1983         vec3_t clipped, p;
1984         vec_t dist, bestdist;
1985         prvm_edict_t *ed;
1986         dp_model_t *model = NULL;
1987         msurface_t *surface;
1988         vec_t *point;
1989         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1990         PRVM_G_FLOAT(OFS_RETURN) = -1;
1991         ed = PRVM_G_EDICT(OFS_PARM0);
1992         if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1993                 return;
1994
1995         // FIXME: implement rotation/scaling
1996         point = PRVM_G_VECTOR(OFS_PARM1);
1997         VectorSubtract(point, ed->fields.client->origin, p);
1998         best = -1;
1999         bestdist = 1000000000;
2000         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2001         {
2002                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2003                 // first see if the nearest point on the surface's box is closer than the previous match
2004                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2005                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2006                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2007                 dist = VectorLength2(clipped);
2008                 if (dist < bestdist)
2009                 {
2010                         // it is, check the nearest point on the actual geometry
2011                         clippointtosurface(model, surface, p, clipped);
2012                         VectorSubtract(clipped, p, clipped);
2013                         dist += VectorLength2(clipped);
2014                         if (dist < bestdist)
2015                         {
2016                                 // that's closer too, store it as the best match
2017                                 best = surfacenum;
2018                                 bestdist = dist;
2019                         }
2020                 }
2021         }
2022         PRVM_G_FLOAT(OFS_RETURN) = best;
2023 }
2024
2025 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
2026 static void VM_CL_getsurfaceclippedpoint(void)
2027 {
2028         prvm_edict_t *ed;
2029         dp_model_t *model;
2030         msurface_t *surface;
2031         vec3_t p, out;
2032         VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
2033         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2034         ed = PRVM_G_EDICT(OFS_PARM0);
2035         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2036                 return;
2037         // FIXME: implement rotation/scaling
2038         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
2039         clippointtosurface(model, surface, p, out);
2040         // FIXME: implement rotation/scaling
2041         VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
2042 }
2043
2044 // #443 void(entity e, entity tagentity, string tagname) setattachment
2045 void VM_CL_setattachment (void)
2046 {
2047         prvm_edict_t *e;
2048         prvm_edict_t *tagentity;
2049         const char *tagname;
2050         prvm_eval_t *v;
2051         int modelindex;
2052         dp_model_t *model;
2053         VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
2054
2055         e = PRVM_G_EDICT(OFS_PARM0);
2056         tagentity = PRVM_G_EDICT(OFS_PARM1);
2057         tagname = PRVM_G_STRING(OFS_PARM2);
2058
2059         if (e == prog->edicts)
2060         {
2061                 VM_Warning("setattachment: can not modify world entity\n");
2062                 return;
2063         }
2064         if (e->priv.server->free)
2065         {
2066                 VM_Warning("setattachment: can not modify free entity\n");
2067                 return;
2068         }
2069
2070         if (tagentity == NULL)
2071                 tagentity = prog->edicts;
2072
2073         v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2074         if (v)
2075                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2076
2077         v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2078         if (v)
2079                 v->_float = 0;
2080         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2081         {
2082                 modelindex = (int)tagentity->fields.client->modelindex;
2083                 model = CL_GetModelByIndex(modelindex);
2084                 if (model)
2085                 {
2086                         v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
2087                         if (v->_float == 0)
2088                                 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);
2089                 }
2090                 else
2091                         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));
2092         }
2093 }
2094
2095 /////////////////////////////////////////
2096 // DP_MD3_TAGINFO extension coded by VorteX
2097
2098 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
2099 {
2100         dp_model_t *model = CL_GetModelFromEdict(e);
2101         if (model)
2102                 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
2103         else
2104                 return -1;
2105 };
2106
2107 // Warnings/errors code:
2108 // 0 - normal (everything all-right)
2109 // 1 - world entity
2110 // 2 - free entity
2111 // 3 - null or non-precached model
2112 // 4 - no tags with requested index
2113 // 5 - runaway loop at attachment chain
2114 extern cvar_t cl_bob;
2115 extern cvar_t cl_bobcycle;
2116 extern cvar_t cl_bobup;
2117 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2118 {
2119         prvm_eval_t *val;
2120         int reqframe, attachloop;
2121         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2122         prvm_edict_t *attachent;
2123         dp_model_t *model;
2124         float scale;
2125
2126         *out = identitymatrix; // warnings and errors return identical matrix
2127
2128         if (ent == prog->edicts)
2129                 return 1;
2130         if (ent->priv.server->free)
2131                 return 2;
2132
2133         model = CL_GetModelFromEdict(ent);
2134
2135         if(!model)
2136                 return 3;
2137
2138         if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
2139                 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
2140         else
2141                 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2142
2143         // get initial tag matrix
2144         if (tagindex)
2145         {
2146                 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2147                 if (ret)
2148                         return ret;
2149         }
2150         else
2151                 tagmatrix = identitymatrix;
2152
2153         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2154         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2155                 attachloop = 0;
2156                 do
2157                 {
2158                         attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2159                         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
2160
2161                         model = CL_GetModelFromEdict(attachent);
2162
2163                         if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
2164                                 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
2165                         else
2166                                 attachmatrix = identitymatrix;
2167
2168                         // apply transformation by child entity matrix
2169                         scale = 1;
2170                         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2171                         if (val && val->_float != 0)
2172                                 scale = val->_float;
2173                         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);
2174                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2175                         Matrix4x4_Copy(&tagmatrix, out);
2176
2177                         // finally transformate by matrix of tag on parent entity
2178                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2179                         Matrix4x4_Copy(&tagmatrix, out);
2180
2181                         ent = attachent;
2182                         attachloop += 1;
2183                         if (attachloop > 255) // prevent runaway looping
2184                                 return 5;
2185                 }
2186                 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
2187         }
2188
2189         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2190         scale = 1;
2191         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2192         if (val && val->_float != 0)
2193                 scale = val->_float;
2194         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2195         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);
2196         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2197
2198         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
2199         {// RENDER_VIEWMODEL magic
2200                 Matrix4x4_Copy(&tagmatrix, out);
2201
2202                 scale = 1;
2203                 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2204                 if (val && val->_float != 0)
2205                         scale = val->_float;
2206
2207                 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);
2208                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2209
2210                 /*
2211                 // Cl_bob, ported from rendering code
2212                 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2213                 {
2214                         double bob, cycle;
2215                         // LordHavoc: this code is *weird*, but not replacable (I think it
2216                         // should be done in QC on the server, but oh well, quake is quake)
2217                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2218                         // degrees (which allows lengthening or squishing the peak or valley)
2219                         cycle = cl.time/cl_bobcycle.value;
2220                         cycle -= (int)cycle;
2221                         if (cycle < cl_bobup.value)
2222                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2223                         else
2224                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2225                         // bob is proportional to velocity in the xy plane
2226                         // (don't count Z, or jumping messes it up)
2227                         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;
2228                         bob = bob*0.3 + bob*0.7*cycle;
2229                         Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2230                 }
2231                 */
2232         }
2233         return 0;
2234 }
2235
2236 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2237 void VM_CL_gettagindex (void)
2238 {
2239         prvm_edict_t *ent;
2240         const char *tag_name;
2241         int modelindex, tag_index;
2242
2243         VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2244
2245         ent = PRVM_G_EDICT(OFS_PARM0);
2246         tag_name = PRVM_G_STRING(OFS_PARM1);
2247         if (ent == prog->edicts)
2248         {
2249                 VM_Warning("gettagindex: can't affect world entity\n");
2250                 return;
2251         }
2252         if (ent->priv.server->free)
2253         {
2254                 VM_Warning("gettagindex: can't affect free entity\n");
2255                 return;
2256         }
2257
2258         modelindex = (int)ent->fields.client->modelindex;
2259         tag_index = 0;
2260         if (modelindex >= MAX_MODELS || (modelindex <= -MAX_MODELS /* client models */))
2261                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2262         else
2263         {
2264                 tag_index = CL_GetTagIndex(ent, tag_name);
2265                 if (tag_index == 0)
2266                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2267         }
2268         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2269 }
2270
2271 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2272 void VM_CL_gettaginfo (void)
2273 {
2274         prvm_edict_t *e;
2275         int tagindex;
2276         matrix4x4_t tag_matrix;
2277         int returncode;
2278
2279         VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2280
2281         e = PRVM_G_EDICT(OFS_PARM0);
2282         tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2283         returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2284         Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2285
2286         switch(returncode)
2287         {
2288                 case 1:
2289                         VM_Warning("gettagindex: can't affect world entity\n");
2290                         break;
2291                 case 2:
2292                         VM_Warning("gettagindex: can't affect free entity\n");
2293                         break;
2294                 case 3:
2295                         Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2296                         break;
2297                 case 4:
2298                         Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2299                         break;
2300                 case 5:
2301                         Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2302                         break;
2303         }
2304 }
2305
2306 //============================================================================
2307
2308 //====================
2309 //QC POLYGON functions
2310 //====================
2311
2312 #define VMPOLYGONS_MAXPOINTS 64
2313
2314 typedef struct vmpolygons_triangle_s
2315 {
2316         rtexture_t              *texture;
2317         int                             drawflag;
2318         unsigned short  elements[3];
2319 }vmpolygons_triangle_t;
2320
2321 typedef struct vmpolygons_s
2322 {
2323         mempool_t               *pool;
2324         qboolean                initialized;
2325
2326         int                             max_vertices;
2327         int                             num_vertices;
2328         float                   *data_vertex3f;
2329         float                   *data_color4f;
2330         float                   *data_texcoord2f;
2331
2332         int                             max_triangles;
2333         int                             num_triangles;
2334         vmpolygons_triangle_t *data_triangles;
2335         unsigned short  *data_sortedelement3s;
2336
2337         qboolean                begin_active;
2338         rtexture_t              *begin_texture;
2339         int                             begin_drawflag;
2340         int                             begin_vertices;
2341         float                   begin_vertex[VMPOLYGONS_MAXPOINTS][3];
2342         float                   begin_color[VMPOLYGONS_MAXPOINTS][4];
2343         float                   begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
2344 } vmpolygons_t;
2345
2346 // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
2347 vmpolygons_t vmpolygons[PRVM_MAXPROGS];
2348
2349 //#304 void() renderscene (EXT_CSQC)
2350 // moved that here to reset the polygons,
2351 // resetting them earlier causes R_Mesh_Draw to be called with numvertices = 0
2352 // --blub
2353 void VM_CL_R_RenderScene (void)
2354 {
2355         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2356         VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
2357         // we need to update any RENDER_VIEWMODEL entities at this point because
2358         // csqc supplies its own view matrix
2359         CL_UpdateViewEntities();
2360         // now draw stuff!
2361         R_RenderView();
2362
2363         polys->num_vertices = polys->num_triangles = 0;
2364 }
2365
2366 static void VM_ResizePolygons(vmpolygons_t *polys)
2367 {
2368         float *oldvertex3f = polys->data_vertex3f;
2369         float *oldcolor4f = polys->data_color4f;
2370         float *oldtexcoord2f = polys->data_texcoord2f;
2371         vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
2372         unsigned short *oldsortedelement3s = polys->data_sortedelement3s;
2373         polys->max_vertices = min(polys->max_triangles*3, 65536);
2374         polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
2375         polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
2376         polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
2377         polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
2378         polys->data_sortedelement3s = (unsigned short *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(unsigned short[3]));
2379         if (polys->num_vertices)
2380         {
2381                 memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
2382                 memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
2383                 memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
2384         }
2385         if (polys->num_triangles)
2386         {
2387                 memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
2388                 memcpy(polys->data_sortedelement3s, oldsortedelement3s, polys->num_triangles*sizeof(unsigned short[3]));
2389         }
2390         if (oldvertex3f)
2391                 Mem_Free(oldvertex3f);
2392         if (oldcolor4f)
2393                 Mem_Free(oldcolor4f);
2394         if (oldtexcoord2f)
2395                 Mem_Free(oldtexcoord2f);
2396         if (oldtriangles)
2397                 Mem_Free(oldtriangles);
2398         if (oldsortedelement3s)
2399                 Mem_Free(oldsortedelement3s);
2400 }
2401
2402 static void VM_InitPolygons (vmpolygons_t* polys)
2403 {
2404         memset(polys, 0, sizeof(*polys));
2405         polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
2406         polys->max_triangles = 1024;
2407         VM_ResizePolygons(polys);
2408         polys->initialized = true;
2409 }
2410
2411 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2412 {
2413         int surfacelistindex;
2414         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2415         R_Mesh_Matrix(&identitymatrix);
2416         GL_CullFace(GL_NONE);
2417         R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
2418         R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
2419         R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
2420         R_SetupGenericShader(true);
2421         for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
2422         {
2423                 int numtriangles = 0;
2424                 rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
2425                 int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
2426                 if(drawflag == DRAWFLAG_ADDITIVE)
2427                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2428                 else if(drawflag == DRAWFLAG_MODULATE)
2429                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2430                 else if(drawflag == DRAWFLAG_2XMODULATE)
2431                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2432                 else
2433                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2434                 R_Mesh_TexBind(0, R_GetTexture(tex));
2435                 numtriangles = 0;
2436                 for (;surfacelistindex < numsurfaces;surfacelistindex++)
2437                 {
2438                         if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag)
2439                                 break;
2440                         VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles);
2441                         numtriangles++;
2442                 }
2443                 R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, polys->data_sortedelement3s, 0, 0);
2444         }
2445 }
2446
2447 void VMPolygons_Store(vmpolygons_t *polys)
2448 {
2449         if (r_refdef.draw2dstage)
2450         {
2451                 // draw the polygon as 2D immediately
2452                 drawqueuemesh_t mesh;
2453                 mesh.texture = polys->begin_texture;
2454                 mesh.num_vertices = polys->begin_vertices;
2455                 mesh.num_triangles = polys->begin_vertices-2;
2456                 mesh.data_element3s = polygonelements;
2457                 mesh.data_vertex3f = polys->begin_vertex[0];
2458                 mesh.data_color4f = polys->begin_color[0];
2459                 mesh.data_texcoord2f = polys->begin_texcoord[0];
2460                 DrawQ_Mesh(&mesh, polys->begin_drawflag);
2461         }
2462         else
2463         {
2464                 // queue the polygon as 3D for sorted transparent rendering later
2465                 int i;
2466                 if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2)
2467                 {
2468                         polys->max_triangles *= 2;
2469                         VM_ResizePolygons(polys);
2470                 }
2471                 if (polys->num_vertices + polys->begin_vertices <= polys->max_vertices)
2472                 {
2473                         // needle in a haystack!
2474                         // polys->num_vertices was used for copying where we actually want to copy begin_vertices
2475                         // that also caused it to not render the first polygon that is added
2476                         // --blub
2477                         memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->begin_vertices * sizeof(float[3]));
2478                         memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->begin_vertices * sizeof(float[4]));
2479                         memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->begin_vertices * sizeof(float[2]));
2480                         for (i = 0;i < polys->begin_vertices-2;i++)
2481                         {
2482                                 polys->data_triangles[polys->num_triangles].texture = polys->begin_texture;
2483                                 polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag;
2484                                 polys->data_triangles[polys->num_triangles].elements[0] = polys->num_vertices;
2485                                 polys->data_triangles[polys->num_triangles].elements[1] = polys->num_vertices + i+1;
2486                                 polys->data_triangles[polys->num_triangles].elements[2] = polys->num_vertices + i+2;
2487                                 polys->num_triangles++;
2488                         }
2489                         polys->num_vertices += polys->begin_vertices;
2490                 }
2491         }
2492         polys->begin_active = false;
2493 }
2494
2495 // TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
2496 // LordHavoc: agreed, this is a mess
2497 void VM_CL_AddPolygonsToMeshQueue (void)
2498 {
2499         int i;
2500         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2501         vec3_t center;
2502
2503         // only add polygons of the currently active prog to the queue - if there is none, we're done
2504         if( !prog )
2505                 return;
2506
2507         if (!polys->num_triangles)
2508                 return;
2509
2510         for (i = 0;i < polys->num_triangles;i++)
2511         {
2512                 VectorMAMAM(1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[0], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[1], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[2], center);
2513                 R_MeshQueue_AddTransparent(center, VM_DrawPolygonCallback, NULL, i, NULL);
2514         }
2515
2516         /*polys->num_triangles = 0; // now done after rendering the scene,
2517           polys->num_vertices = 0;  // otherwise it's not rendered at all and prints an error message --blub */
2518 }
2519
2520 //void(string texturename, float flag) R_BeginPolygon
2521 void VM_CL_R_PolygonBegin (void)
2522 {
2523         const char              *picname;
2524         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2525
2526         VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
2527
2528         if (!polys->initialized)
2529                 VM_InitPolygons(polys);
2530         if (polys->begin_active)
2531         {
2532                 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
2533                 return;
2534         }
2535         picname = PRVM_G_STRING(OFS_PARM0);
2536         polys->begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white;
2537         polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
2538         polys->begin_vertices = 0;
2539         polys->begin_active = true;
2540 }
2541
2542 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2543 void VM_CL_R_PolygonVertex (void)
2544 {
2545         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2546
2547         VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2548
2549         if (!polys->begin_active)
2550         {
2551                 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2552                 return;
2553         }
2554
2555         if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
2556         {
2557                 VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2558                 return;
2559         }
2560
2561         polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0];
2562         polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1];
2563         polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2];
2564         polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0];
2565         polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1];
2566         polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0];
2567         polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1];
2568         polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2];
2569         polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3);
2570         polys->begin_vertices++;
2571 }
2572
2573 //void() R_EndPolygon
2574 void VM_CL_R_PolygonEnd (void)
2575 {
2576         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2577
2578         VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2579         if (!polys->begin_active)
2580         {
2581                 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2582                 return;
2583         }
2584         polys->begin_active = false;
2585         if (polys->begin_vertices >= 3)
2586                 VMPolygons_Store(polys);
2587         else
2588                 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
2589 }
2590
2591 static vmpolygons_t debugPolys;
2592
2593 void Debug_PolygonBegin(const char *picname, int drawflag)
2594 {
2595         if(!debugPolys.initialized)
2596                 VM_InitPolygons(&debugPolys);
2597         if(debugPolys.begin_active)
2598         {
2599                 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2600                 return;
2601         }
2602         debugPolys.begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white;
2603         debugPolys.begin_drawflag = drawflag;
2604         debugPolys.begin_vertices = 0;
2605         debugPolys.begin_active = true;
2606 }
2607
2608 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2609 {
2610         if(!debugPolys.begin_active)
2611         {
2612                 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2613                 return;
2614         }
2615
2616         if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS)
2617         {
2618                 Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2619                 return;
2620         }
2621
2622         debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x;
2623         debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y;
2624         debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z;
2625         debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s;
2626         debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t;
2627         debugPolys.begin_color[debugPolys.begin_vertices][0] = r;
2628         debugPolys.begin_color[debugPolys.begin_vertices][1] = g;
2629         debugPolys.begin_color[debugPolys.begin_vertices][2] = b;
2630         debugPolys.begin_color[debugPolys.begin_vertices][3] = a;
2631         debugPolys.begin_vertices++;
2632 }
2633
2634 void Debug_PolygonEnd(void)
2635 {
2636         if (!debugPolys.begin_active)
2637         {
2638                 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2639                 return;
2640         }
2641         debugPolys.begin_active = false;
2642         if (debugPolys.begin_vertices >= 3)
2643                 VMPolygons_Store(&debugPolys);
2644         else
2645                 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
2646 }
2647
2648 /*
2649 =============
2650 CL_CheckBottom
2651
2652 Returns false if any part of the bottom of the entity is off an edge that
2653 is not a staircase.
2654
2655 =============
2656 */
2657 qboolean CL_CheckBottom (prvm_edict_t *ent)
2658 {
2659         vec3_t  mins, maxs, start, stop;
2660         trace_t trace;
2661         int             x, y;
2662         float   mid, bottom;
2663
2664         VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2665         VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2666
2667 // if all of the points under the corners are solid world, don't bother
2668 // with the tougher checks
2669 // the corners must be within 16 of the midpoint
2670         start[2] = mins[2] - 1;
2671         for     (x=0 ; x<=1 ; x++)
2672                 for     (y=0 ; y<=1 ; y++)
2673                 {
2674                         start[0] = x ? maxs[0] : mins[0];
2675                         start[1] = y ? maxs[1] : mins[1];
2676                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2677                                 goto realcheck;
2678                 }
2679
2680         return true;            // we got out easy
2681
2682 realcheck:
2683 //
2684 // check it for real...
2685 //
2686         start[2] = mins[2];
2687
2688 // the midpoint must be within 16 of the bottom
2689         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2690         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2691         stop[2] = start[2] - 2*sv_stepheight.value;
2692         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2693
2694         if (trace.fraction == 1.0)
2695                 return false;
2696         mid = bottom = trace.endpos[2];
2697
2698 // the corners must be within 16 of the midpoint
2699         for     (x=0 ; x<=1 ; x++)
2700                 for     (y=0 ; y<=1 ; y++)
2701                 {
2702                         start[0] = stop[0] = x ? maxs[0] : mins[0];
2703                         start[1] = stop[1] = y ? maxs[1] : mins[1];
2704
2705                         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2706
2707                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2708                                 bottom = trace.endpos[2];
2709                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2710                                 return false;
2711                 }
2712
2713         return true;
2714 }
2715
2716 /*
2717 =============
2718 CL_movestep
2719
2720 Called by monster program code.
2721 The move will be adjusted for slopes and stairs, but if the move isn't
2722 possible, no move is done and false is returned
2723 =============
2724 */
2725 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2726 {
2727         float           dz;
2728         vec3_t          oldorg, neworg, end, traceendpos;
2729         trace_t         trace;
2730         int                     i;
2731         prvm_edict_t            *enemy;
2732         prvm_eval_t     *val;
2733
2734 // try the move
2735         VectorCopy (ent->fields.client->origin, oldorg);
2736         VectorAdd (ent->fields.client->origin, move, neworg);
2737
2738 // flying monsters don't step up
2739         if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2740         {
2741         // try one move with vertical motion, then one without
2742                 for (i=0 ; i<2 ; i++)
2743                 {
2744                         VectorAdd (ent->fields.client->origin, move, neworg);
2745                         enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2746                         if (i == 0 && enemy != prog->edicts)
2747                         {
2748                                 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2749                                 if (dz > 40)
2750                                         neworg[2] -= 8;
2751                                 if (dz < 30)
2752                                         neworg[2] += 8;
2753                         }
2754                         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);
2755                         if (settrace)
2756                                 VM_SetTraceGlobals(&trace);
2757
2758                         if (trace.fraction == 1)
2759                         {
2760                                 VectorCopy(trace.endpos, traceendpos);
2761                                 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2762                                         return false;   // swim monster left water
2763
2764                                 VectorCopy (traceendpos, ent->fields.client->origin);
2765                                 if (relink)
2766                                         CL_LinkEdict(ent);
2767                                 return true;
2768                         }
2769
2770                         if (enemy == prog->edicts)
2771                                 break;
2772                 }
2773
2774                 return false;
2775         }
2776
2777 // push down from a step height above the wished position
2778         neworg[2] += sv_stepheight.value;
2779         VectorCopy (neworg, end);
2780         end[2] -= sv_stepheight.value*2;
2781
2782         trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2783         if (settrace)
2784                 VM_SetTraceGlobals(&trace);
2785
2786         if (trace.startsolid)
2787         {
2788                 neworg[2] -= sv_stepheight.value;
2789                 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2790                 if (settrace)
2791                         VM_SetTraceGlobals(&trace);
2792                 if (trace.startsolid)
2793                         return false;
2794         }
2795         if (trace.fraction == 1)
2796         {
2797         // if monster had the ground pulled out, go ahead and fall
2798                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2799                 {
2800                         VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2801                         if (relink)
2802                                 CL_LinkEdict(ent);
2803                         ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2804                         return true;
2805                 }
2806
2807                 return false;           // walked off an edge
2808         }
2809
2810 // check point traces down for dangling corners
2811         VectorCopy (trace.endpos, ent->fields.client->origin);
2812
2813         if (!CL_CheckBottom (ent))
2814         {
2815                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2816                 {       // entity had floor mostly pulled out from underneath it
2817                         // and is trying to correct
2818                         if (relink)
2819                                 CL_LinkEdict(ent);
2820                         return true;
2821                 }
2822                 VectorCopy (oldorg, ent->fields.client->origin);
2823                 return false;
2824         }
2825
2826         if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2827                 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2828
2829         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2830                 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2831
2832 // the move is ok
2833         if (relink)
2834                 CL_LinkEdict(ent);
2835         return true;
2836 }
2837
2838 /*
2839 ===============
2840 VM_CL_walkmove
2841
2842 float(float yaw, float dist[, settrace]) walkmove
2843 ===============
2844 */
2845 static void VM_CL_walkmove (void)
2846 {
2847         prvm_edict_t    *ent;
2848         float   yaw, dist;
2849         vec3_t  move;
2850         mfunction_t     *oldf;
2851         int     oldself;
2852         qboolean        settrace;
2853
2854         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2855
2856         // assume failure if it returns early
2857         PRVM_G_FLOAT(OFS_RETURN) = 0;
2858
2859         ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2860         if (ent == prog->edicts)
2861         {
2862                 VM_Warning("walkmove: can not modify world entity\n");
2863                 return;
2864         }
2865         if (ent->priv.server->free)
2866         {
2867                 VM_Warning("walkmove: can not modify free entity\n");
2868                 return;
2869         }
2870         yaw = PRVM_G_FLOAT(OFS_PARM0);
2871         dist = PRVM_G_FLOAT(OFS_PARM1);
2872         settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2873
2874         if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2875                 return;
2876
2877         yaw = yaw*M_PI*2 / 360;
2878
2879         move[0] = cos(yaw)*dist;
2880         move[1] = sin(yaw)*dist;
2881         move[2] = 0;
2882
2883 // save program state, because CL_movestep may call other progs
2884         oldf = prog->xfunction;
2885         oldself = prog->globals.client->self;
2886
2887         PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2888
2889
2890 // restore program state
2891         prog->xfunction = oldf;
2892         prog->globals.client->self = oldself;
2893 }
2894
2895 /*
2896 ===============
2897 VM_CL_serverkey
2898
2899 string(string key) serverkey
2900 ===============
2901 */
2902 void VM_CL_serverkey(void)
2903 {
2904         char string[VM_STRINGTEMP_LENGTH];
2905         VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2906         InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2907         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2908 }
2909
2910 //============================================================================
2911
2912 // To create a almost working builtin file from this replace:
2913 // "^NULL.*" with ""
2914 // "^{.*//.*}:Wh\(.*\)" with "\1"
2915 // "\:" with "//"
2916 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
2917 // "\n\n+" with "\n\n"
2918
2919 prvm_builtin_t vm_cl_builtins[] = {
2920 NULL,                                                   // #0 NULL function (not callable) (QUAKE)
2921 VM_CL_makevectors,                              // #1 void(vector ang) makevectors (QUAKE)
2922 VM_CL_setorigin,                                // #2 void(entity e, vector o) setorigin (QUAKE)
2923 VM_CL_setmodel,                                 // #3 void(entity e, string m) setmodel (QUAKE)
2924 VM_CL_setsize,                                  // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2925 NULL,                                                   // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2926 VM_break,                                               // #6 void() break (QUAKE)
2927 VM_random,                                              // #7 float() random (QUAKE)
2928 VM_CL_sound,                                    // #8 void(entity e, float chan, string samp) sound (QUAKE)
2929 VM_normalize,                                   // #9 vector(vector v) normalize (QUAKE)
2930 VM_error,                                               // #10 void(string e) error (QUAKE)
2931 VM_objerror,                                    // #11 void(string e) objerror (QUAKE)
2932 VM_vlen,                                                // #12 float(vector v) vlen (QUAKE)
2933 VM_vectoyaw,                                    // #13 float(vector v) vectoyaw (QUAKE)
2934 VM_CL_spawn,                                    // #14 entity() spawn (QUAKE)
2935 VM_remove,                                              // #15 void(entity e) remove (QUAKE)
2936 VM_CL_traceline,                                // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
2937 NULL,                                                   // #17 entity() checkclient (QUAKE)
2938 VM_find,                                                // #18 entity(entity start, .string fld, string match) find (QUAKE)
2939 VM_precache_sound,                              // #19 void(string s) precache_sound (QUAKE)
2940 VM_CL_precache_model,                   // #20 void(string s) precache_model (QUAKE)
2941 NULL,                                                   // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2942 VM_CL_findradius,                               // #22 entity(vector org, float rad) findradius (QUAKE)
2943 NULL,                                                   // #23 void(string s, ...) bprint (QUAKE)
2944 NULL,                                                   // #24 void(entity client, string s, ...) sprint (QUAKE)
2945 VM_dprint,                                              // #25 void(string s, ...) dprint (QUAKE)
2946 VM_ftos,                                                // #26 string(float f) ftos (QUAKE)
2947 VM_vtos,                                                // #27 string(vector v) vtos (QUAKE)
2948 VM_coredump,                                    // #28 void() coredump (QUAKE)
2949 VM_traceon,                                             // #29 void() traceon (QUAKE)
2950 VM_traceoff,                                    // #30 void() traceoff (QUAKE)
2951 VM_eprint,                                              // #31 void(entity e) eprint (QUAKE)
2952 VM_CL_walkmove,                                 // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
2953 NULL,                                                   // #33 (QUAKE)
2954 VM_CL_droptofloor,                              // #34 float() droptofloor (QUAKE)
2955 VM_CL_lightstyle,                               // #35 void(float style, string value) lightstyle (QUAKE)
2956 VM_rint,                                                // #36 float(float v) rint (QUAKE)
2957 VM_floor,                                               // #37 float(float v) floor (QUAKE)
2958 VM_ceil,                                                // #38 float(float v) ceil (QUAKE)
2959 NULL,                                                   // #39 (QUAKE)
2960 VM_CL_checkbottom,                              // #40 float(entity e) checkbottom (QUAKE)
2961 VM_CL_pointcontents,                    // #41 float(vector v) pointcontents (QUAKE)
2962 NULL,                                                   // #42 (QUAKE)
2963 VM_fabs,                                                // #43 float(float f) fabs (QUAKE)
2964 NULL,                                                   // #44 vector(entity e, float speed) aim (QUAKE)
2965 VM_cvar,                                                // #45 float(string s) cvar (QUAKE)
2966 VM_localcmd,                                    // #46 void(string s) localcmd (QUAKE)
2967 VM_nextent,                                             // #47 entity(entity e) nextent (QUAKE)
2968 VM_CL_particle,                                 // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2969 VM_changeyaw,                                   // #49 void() ChangeYaw (QUAKE)
2970 NULL,                                                   // #50 (QUAKE)
2971 VM_vectoangles,                                 // #51 vector(vector v) vectoangles (QUAKE)
2972 NULL,                                                   // #52 void(float to, float f) WriteByte (QUAKE)
2973 NULL,                                                   // #53 void(float to, float f) WriteChar (QUAKE)
2974 NULL,                                                   // #54 void(float to, float f) WriteShort (QUAKE)
2975 NULL,                                                   // #55 void(float to, float f) WriteLong (QUAKE)
2976 NULL,                                                   // #56 void(float to, float f) WriteCoord (QUAKE)
2977 NULL,                                                   // #57 void(float to, float f) WriteAngle (QUAKE)
2978 NULL,                                                   // #58 void(float to, string s) WriteString (QUAKE)
2979 NULL,                                                   // #59 (QUAKE)
2980 VM_sin,                                                 // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2981 VM_cos,                                                 // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2982 VM_sqrt,                                                // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2983 VM_changepitch,                                 // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2984 VM_CL_tracetoss,                                // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2985 VM_etos,                                                // #65 string(entity ent) etos (DP_QC_ETOS)
2986 NULL,                                                   // #66 (QUAKE)
2987 NULL,                                                   // #67 void(float step) movetogoal (QUAKE)
2988 VM_precache_file,                               // #68 string(string s) precache_file (QUAKE)
2989 VM_CL_makestatic,                               // #69 void(entity e) makestatic (QUAKE)
2990 NULL,                                                   // #70 void(string s) changelevel (QUAKE)
2991 NULL,                                                   // #71 (QUAKE)
2992 VM_cvar_set,                                    // #72 void(string var, string val) cvar_set (QUAKE)
2993 NULL,                                                   // #73 void(entity client, strings) centerprint (QUAKE)
2994 VM_CL_ambientsound,                             // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2995 VM_CL_precache_model,                   // #75 string(string s) precache_model2 (QUAKE)
2996 VM_precache_sound,                              // #76 string(string s) precache_sound2 (QUAKE)
2997 VM_precache_file,                               // #77 string(string s) precache_file2 (QUAKE)
2998 NULL,                                                   // #78 void(entity e) setspawnparms (QUAKE)
2999 NULL,                                                   // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3000 NULL,                                                   // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3001 VM_stof,                                                // #81 float(string s) stof (FRIK_FILE)
3002 NULL,                                                   // #82 void(vector where, float set) multicast (QUAKEWORLD)
3003 NULL,                                                   // #83 (QUAKE)
3004 NULL,                                                   // #84 (QUAKE)
3005 NULL,                                                   // #85 (QUAKE)
3006 NULL,                                                   // #86 (QUAKE)
3007 NULL,                                                   // #87 (QUAKE)
3008 NULL,                                                   // #88 (QUAKE)
3009 NULL,                                                   // #89 (QUAKE)
3010 VM_CL_tracebox,                                 // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3011 VM_randomvec,                                   // #91 vector() randomvec (DP_QC_RANDOMVEC)
3012 VM_CL_getlight,                                 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3013 VM_registercvar,                                // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3014 VM_min,                                                 // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3015 VM_max,                                                 // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3016 VM_bound,                                               // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3017 VM_pow,                                                 // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3018 VM_findfloat,                                   // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3019 VM_checkextension,                              // #99 float(string s) checkextension (the basis of the extension system)
3020 // FrikaC and Telejano range #100-#199
3021 NULL,                                                   // #100
3022 NULL,                                                   // #101
3023 NULL,                                                   // #102
3024 NULL,                                                   // #103
3025 NULL,                                                   // #104
3026 NULL,                                                   // #105
3027 NULL,                                                   // #106
3028 NULL,                                                   // #107
3029 NULL,                                                   // #108
3030 NULL,                                                   // #109
3031 VM_fopen,                                               // #110 float(string filename, float mode) fopen (FRIK_FILE)
3032 VM_fclose,                                              // #111 void(float fhandle) fclose (FRIK_FILE)
3033 VM_fgets,                                               // #112 string(float fhandle) fgets (FRIK_FILE)
3034 VM_fputs,                                               // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3035 VM_strlen,                                              // #114 float(string s) strlen (FRIK_FILE)
3036 VM_strcat,                                              // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3037 VM_substring,                                   // #116 string(string s, float start, float length) substring (FRIK_FILE)
3038 VM_stov,                                                // #117 vector(string) stov (FRIK_FILE)
3039 VM_strzone,                                             // #118 string(string s) strzone (FRIK_FILE)
3040 VM_strunzone,                                   // #119 void(string s) strunzone (FRIK_FILE)
3041 NULL,                                                   // #120
3042 NULL,                                                   // #121
3043 NULL,                                                   // #122
3044 NULL,                                                   // #123
3045 NULL,                                                   // #124
3046 NULL,                                                   // #125
3047 NULL,                                                   // #126
3048 NULL,                                                   // #127
3049 NULL,                                                   // #128
3050 NULL,                                                   // #129
3051 NULL,                                                   // #130
3052 NULL,                                                   // #131
3053 NULL,                                                   // #132
3054 NULL,                                                   // #133
3055 NULL,                                                   // #134
3056 NULL,                                                   // #135
3057 NULL,                                                   // #136
3058 NULL,                                                   // #137
3059 NULL,                                                   // #138
3060 NULL,                                                   // #139
3061 NULL,                                                   // #140
3062 NULL,                                                   // #141
3063 NULL,                                                   // #142
3064 NULL,                                                   // #143
3065 NULL,                                                   // #144
3066 NULL,                                                   // #145
3067 NULL,                                                   // #146
3068 NULL,                                                   // #147
3069 NULL,                                                   // #148
3070 NULL,                                                   // #149
3071 NULL,                                                   // #150
3072 NULL,                                                   // #151
3073 NULL,                                                   // #152
3074 NULL,                                                   // #153
3075 NULL,                                                   // #154
3076 NULL,                                                   // #155
3077 NULL,                                                   // #156
3078 NULL,                                                   // #157
3079 NULL,                                                   // #158
3080 NULL,                                                   // #159
3081 NULL,                                                   // #160
3082 NULL,                                                   // #161
3083 NULL,                                                   // #162
3084 NULL,                                                   // #163
3085 NULL,                                                   // #164
3086 NULL,                                                   // #165
3087 NULL,                                                   // #166
3088 NULL,                                                   // #167
3089 NULL,                                                   // #168
3090 NULL,                                                   // #169
3091 NULL,                                                   // #170
3092 NULL,                                                   // #171
3093 NULL,                                                   // #172
3094 NULL,                                                   // #173
3095 NULL,                                                   // #174
3096 NULL,                                                   // #175
3097 NULL,                                                   // #176
3098 NULL,                                                   // #177
3099 NULL,                                                   // #178
3100 NULL,                                                   // #179
3101 NULL,                                                   // #180
3102 NULL,                                                   // #181
3103 NULL,                                                   // #182
3104 NULL,                                                   // #183
3105 NULL,                                                   // #184
3106 NULL,                                                   // #185
3107 NULL,                                                   // #186
3108 NULL,                                                   // #187
3109 NULL,                                                   // #188
3110 NULL,                                                   // #189
3111 NULL,                                                   // #190
3112 NULL,                                                   // #191
3113 NULL,                                                   // #192
3114 NULL,                                                   // #193
3115 NULL,                                                   // #194
3116 NULL,                                                   // #195
3117 NULL,                                                   // #196
3118 NULL,                                                   // #197
3119 NULL,                                                   // #198
3120 NULL,                                                   // #199
3121 // FTEQW range #200-#299
3122 NULL,                                                   // #200
3123 NULL,                                                   // #201
3124 NULL,                                                   // #202
3125 NULL,                                                   // #203
3126 NULL,                                                   // #204
3127 NULL,                                                   // #205
3128 NULL,                                                   // #206
3129 NULL,                                                   // #207
3130 NULL,                                                   // #208
3131 NULL,                                                   // #209
3132 NULL,                                                   // #210
3133 NULL,                                                   // #211
3134 NULL,                                                   // #212
3135 NULL,                                                   // #213
3136 NULL,                                                   // #214
3137 NULL,                                                   // #215
3138 NULL,                                                   // #216
3139 NULL,                                                   // #217
3140 VM_bitshift,                                    // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3141 NULL,                                                   // #219
3142 NULL,                                                   // #220
3143 VM_strstrofs,                                   // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3144 VM_str2chr,                                             // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3145 VM_chr2str,                                             // #223 string(float c, ...) chr2str (FTE_STRINGS)
3146 VM_strconv,                                             // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3147 VM_strpad,                                              // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3148 VM_infoadd,                                             // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3149 VM_infoget,                                             // #227 string(string info, string key) infoget (FTE_STRINGS)
3150 VM_strncmp,                                             // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3151 VM_strncasecmp,                                 // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3152 VM_strncasecmp,                                 // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3153 NULL,                                                   // #231
3154 NULL,                                                   // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3155 NULL,                                                   // #233
3156 NULL,                                                   // #234
3157 NULL,                                                   // #235
3158 NULL,                                                   // #236
3159 NULL,                                                   // #237
3160 NULL,                                                   // #238
3161 NULL,                                                   // #239
3162 NULL,                                                   // #240
3163 NULL,                                                   // #241
3164 NULL,                                                   // #242
3165 NULL,                                                   // #243
3166 NULL,                                                   // #244
3167 NULL,                                                   // #245
3168 NULL,                                                   // #246
3169 NULL,                                                   // #247
3170 NULL,                                                   // #248
3171 NULL,                                                   // #249
3172 NULL,                                                   // #250
3173 NULL,                                                   // #251
3174 NULL,                                                   // #252
3175 NULL,                                                   // #253
3176 NULL,                                                   // #254
3177 NULL,                                                   // #255
3178 NULL,                                                   // #256
3179 NULL,                                                   // #257
3180 NULL,                                                   // #258
3181 NULL,                                                   // #259
3182 NULL,                                                   // #260
3183 NULL,                                                   // #261
3184 NULL,                                                   // #262
3185 NULL,                                                   // #263
3186 NULL,                                                   // #264
3187 NULL,                                                   // #265
3188 NULL,                                                   // #266
3189 NULL,                                                   // #267
3190 NULL,                                                   // #268
3191 NULL,                                                   // #269
3192 NULL,                                                   // #270