]> icculus.org git repositories - divverent/darkplaces.git/blob - clvm_cmds.c
don't ungrab mouse in loading screens in fullscreen
[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         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);
1080 }
1081
1082 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
1083 static void VM_CL_pointparticles (void)
1084 {
1085         int                     i, n;
1086         float           *f, *v;
1087         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
1088         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1089         f = PRVM_G_VECTOR(OFS_PARM1);
1090         v = PRVM_G_VECTOR(OFS_PARM2);
1091         n = (int)PRVM_G_FLOAT(OFS_PARM3);
1092         CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1093 }
1094
1095 //#342 string(float keynum) getkeybind (EXT_CSQC)
1096 static void VM_CL_getkeybind (void)
1097 {
1098         VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
1099         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
1100 }
1101
1102 //#343 void(float usecursor) setcursormode (EXT_CSQC)
1103 static void VM_CL_setcursormode (void)
1104 {
1105         VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
1106         cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
1107         cl_ignoremousemoves = 2;
1108 }
1109
1110 //#344 vector() getmousepos (EXT_CSQC)
1111 static void VM_CL_getmousepos(void)
1112 {
1113         VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
1114
1115         if (cl.csqc_wantsmousemove)
1116                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
1117         else
1118                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
1119 }
1120
1121 //#345 float(float framenum) getinputstate (EXT_CSQC)
1122 static void VM_CL_getinputstate (void)
1123 {
1124         int i, frame;
1125         VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1126         frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1127         for (i = 0;i < CL_MAX_USERCMDS;i++)
1128         {
1129                 if (cl.movecmd[i].sequence == frame)
1130                 {
1131                         VectorCopy(cl.movecmd[i].viewangles, prog->globals.client->input_angles);
1132                         prog->globals.client->input_buttons = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?)
1133                         prog->globals.client->input_movevalues[0] = cl.movecmd[i].forwardmove;
1134                         prog->globals.client->input_movevalues[1] = cl.movecmd[i].sidemove;
1135                         prog->globals.client->input_movevalues[2] = cl.movecmd[i].upmove;
1136                         prog->globals.client->input_timelength = cl.movecmd[i].frametime;
1137                         if(cl.movecmd[i].crouch)
1138                         {
1139                                 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1140                                 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1141                         }
1142                         else
1143                         {
1144                                 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1145                                 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1146                         }
1147                 }
1148         }
1149 }
1150
1151 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1152 static void VM_CL_setsensitivityscale (void)
1153 {
1154         VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1155         cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1156 }
1157
1158 //#347 void() runstandardplayerphysics (EXT_CSQC)
1159 static void VM_CL_runplayerphysics (void)
1160 {
1161 }
1162
1163 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1164 static void VM_CL_getplayerkey (void)
1165 {
1166         int                     i;
1167         char            t[128];
1168         const char      *c;
1169
1170         VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1171
1172         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1173         c = PRVM_G_STRING(OFS_PARM1);
1174         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1175         Sbar_SortFrags();
1176
1177         if (i < 0)
1178                 i = Sbar_GetSortedPlayerIndex(-1-i);
1179         if(i < 0 || i >= cl.maxclients)
1180                 return;
1181
1182         t[0] = 0;
1183
1184         if(!strcasecmp(c, "name"))
1185                 strlcpy(t, cl.scores[i].name, sizeof(t));
1186         else
1187                 if(!strcasecmp(c, "frags"))
1188                         sprintf(t, "%i", cl.scores[i].frags);
1189         else
1190                 if(!strcasecmp(c, "ping"))
1191                         sprintf(t, "%i", cl.scores[i].qw_ping);
1192         else
1193                 if(!strcasecmp(c, "pl"))
1194                         sprintf(t, "%i", cl.scores[i].qw_packetloss);
1195         else
1196                 if(!strcasecmp(c, "entertime"))
1197                         sprintf(t, "%f", cl.scores[i].qw_entertime);
1198         else
1199                 if(!strcasecmp(c, "colors"))
1200                         sprintf(t, "%i", cl.scores[i].colors);
1201         else
1202                 if(!strcasecmp(c, "topcolor"))
1203                         sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1204         else
1205                 if(!strcasecmp(c, "bottomcolor"))
1206                         sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1207         else
1208                 if(!strcasecmp(c, "viewentity"))
1209                         sprintf(t, "%i", i+1);
1210         if(!t[0])
1211                 return;
1212         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1213 }
1214
1215 //#349 float() isdemo (EXT_CSQC)
1216 static void VM_CL_isdemo (void)
1217 {
1218         VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1219         PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1220 }
1221
1222 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1223 static void VM_CL_setlistener (void)
1224 {
1225         VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1226         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));
1227         cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1228 }
1229
1230 //#352 void(string cmdname) registercommand (EXT_CSQC)
1231 static void VM_CL_registercmd (void)
1232 {
1233         char *t;
1234         VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1235         if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1236         {
1237                 size_t alloclen;
1238
1239                 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1240                 t = (char *)Z_Malloc(alloclen);
1241                 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1242                 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1243         }
1244         else
1245                 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1246
1247 }
1248
1249 //#360 float() readbyte (EXT_CSQC)
1250 static void VM_CL_ReadByte (void)
1251 {
1252         VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1253         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1254 }
1255
1256 //#361 float() readchar (EXT_CSQC)
1257 static void VM_CL_ReadChar (void)
1258 {
1259         VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1260         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1261 }
1262
1263 //#362 float() readshort (EXT_CSQC)
1264 static void VM_CL_ReadShort (void)
1265 {
1266         VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1267         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1268 }
1269
1270 //#363 float() readlong (EXT_CSQC)
1271 static void VM_CL_ReadLong (void)
1272 {
1273         VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1274         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1275 }
1276
1277 //#364 float() readcoord (EXT_CSQC)
1278 static void VM_CL_ReadCoord (void)
1279 {
1280         VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1281         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1282 }
1283
1284 //#365 float() readangle (EXT_CSQC)
1285 static void VM_CL_ReadAngle (void)
1286 {
1287         VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1288         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1289 }
1290
1291 //#366 string() readstring (EXT_CSQC)
1292 static void VM_CL_ReadString (void)
1293 {
1294         VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1295         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1296 }
1297
1298 //#367 float() readfloat (EXT_CSQC)
1299 static void VM_CL_ReadFloat (void)
1300 {
1301         VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1302         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1303 }
1304
1305 //////////////////////////////////////////////////////////
1306
1307 static void VM_CL_makestatic (void)
1308 {
1309         prvm_edict_t *ent;
1310
1311         VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1312
1313         ent = PRVM_G_EDICT(OFS_PARM0);
1314         if (ent == prog->edicts)
1315         {
1316                 VM_Warning("makestatic: can not modify world entity\n");
1317                 return;
1318         }
1319         if (ent->priv.server->free)
1320         {
1321                 VM_Warning("makestatic: can not modify free entity\n");
1322                 return;
1323         }
1324
1325         if (cl.num_static_entities < cl.max_static_entities)
1326         {
1327                 int renderflags;
1328                 prvm_eval_t *val;
1329                 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1330
1331                 // copy it to the current state
1332                 memset(staticent, 0, sizeof(*staticent));
1333                 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1334                 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1335                 staticent->render.framelerp = 0;
1336                 // make torchs play out of sync
1337                 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1338                 staticent->render.skinnum = (int)ent->fields.client->skin;
1339                 staticent->render.effects = (int)ent->fields.client->effects;
1340                 staticent->render.alpha = 1;
1341                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1342                 staticent->render.scale = 1;
1343                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1344                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1345
1346                 renderflags = 0;
1347                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1348                 if (renderflags & RF_USEAXIS)
1349                 {
1350                         vec3_t left;
1351                         VectorNegate(prog->globals.client->v_right, left);
1352                         Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1353                         Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1354                 }
1355                 else
1356                         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);
1357
1358                 // either fullbright or lit
1359                 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1360                         staticent->render.flags |= RENDER_LIGHT;
1361                 // turn off shadows from transparent objects
1362                 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1363                         staticent->render.flags |= RENDER_SHADOW;
1364
1365                 CL_UpdateRenderEntity(&staticent->render);
1366         }
1367         else
1368                 Con_Printf("Too many static entities");
1369
1370 // throw the entity away now
1371         PRVM_ED_Free (ent);
1372 }
1373
1374 //=================================================================//
1375
1376 /*
1377 =================
1378 VM_CL_copyentity
1379
1380 copies data from one entity to another
1381
1382 copyentity(src, dst)
1383 =================
1384 */
1385 static void VM_CL_copyentity (void)
1386 {
1387         prvm_edict_t *in, *out;
1388         VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1389         in = PRVM_G_EDICT(OFS_PARM0);
1390         if (in == prog->edicts)
1391         {
1392                 VM_Warning("copyentity: can not read world entity\n");
1393                 return;
1394         }
1395         if (in->priv.server->free)
1396         {
1397                 VM_Warning("copyentity: can not read free entity\n");
1398                 return;
1399         }
1400         out = PRVM_G_EDICT(OFS_PARM1);
1401         if (out == prog->edicts)
1402         {
1403                 VM_Warning("copyentity: can not modify world entity\n");
1404                 return;
1405         }
1406         if (out->priv.server->free)
1407         {
1408                 VM_Warning("copyentity: can not modify free entity\n");
1409                 return;
1410         }
1411         memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1412         CL_LinkEdict(out);
1413 }
1414
1415 //=================================================================//
1416
1417 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1418 static void VM_CL_effect (void)
1419 {
1420         VM_SAFEPARMCOUNT(5, VM_CL_effect);
1421         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));
1422 }
1423
1424 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1425 static void VM_CL_te_blood (void)
1426 {
1427         float   *pos;
1428         vec3_t  pos2;
1429         VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1430         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1431                 return;
1432         pos = PRVM_G_VECTOR(OFS_PARM0);
1433         CL_FindNonSolidLocation(pos, pos2, 4);
1434         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1435 }
1436
1437 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1438 static void VM_CL_te_bloodshower (void)
1439 {
1440         vec_t speed;
1441         vec3_t vel1, vel2;
1442         VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1443         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1444                 return;
1445         speed = PRVM_G_FLOAT(OFS_PARM2);
1446         vel1[0] = -speed;
1447         vel1[1] = -speed;
1448         vel1[2] = -speed;
1449         vel2[0] = speed;
1450         vel2[1] = speed;
1451         vel2[2] = speed;
1452         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1453 }
1454
1455 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1456 static void VM_CL_te_explosionrgb (void)
1457 {
1458         float           *pos;
1459         vec3_t          pos2;
1460         matrix4x4_t     tempmatrix;
1461         VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1462         pos = PRVM_G_VECTOR(OFS_PARM0);
1463         CL_FindNonSolidLocation(pos, pos2, 10);
1464         CL_ParticleExplosion(pos2);
1465         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1466         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);
1467 }
1468
1469 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1470 static void VM_CL_te_particlecube (void)
1471 {
1472         VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1473         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));
1474 }
1475
1476 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1477 static void VM_CL_te_particlerain (void)
1478 {
1479         VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1480         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);
1481 }
1482
1483 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1484 static void VM_CL_te_particlesnow (void)
1485 {
1486         VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1487         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);
1488 }
1489
1490 // #411 void(vector org, vector vel, float howmany) te_spark
1491 static void VM_CL_te_spark (void)
1492 {
1493         float           *pos;
1494         vec3_t          pos2;
1495         VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1496
1497         pos = PRVM_G_VECTOR(OFS_PARM0);
1498         CL_FindNonSolidLocation(pos, pos2, 4);
1499         CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1500 }
1501
1502 extern cvar_t cl_sound_ric_gunshot;
1503 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1504 static void VM_CL_te_gunshotquad (void)
1505 {
1506         float           *pos;
1507         vec3_t          pos2;
1508         int                     rnd;
1509         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1510
1511         pos = PRVM_G_VECTOR(OFS_PARM0);
1512         CL_FindNonSolidLocation(pos, pos2, 4);
1513         CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1514         if(cl_sound_ric_gunshot.integer >= 2)
1515         {
1516                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1517                 else
1518                 {
1519                         rnd = rand() & 3;
1520                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1521                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1522                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1523                 }
1524         }
1525 }
1526
1527 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1528 static void VM_CL_te_spikequad (void)
1529 {
1530         float           *pos;
1531         vec3_t          pos2;
1532         int                     rnd;
1533         VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1534
1535         pos = PRVM_G_VECTOR(OFS_PARM0);
1536         CL_FindNonSolidLocation(pos, pos2, 4);
1537         CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1538         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1539         else
1540         {
1541                 rnd = rand() & 3;
1542                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1543                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1544                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1545         }
1546 }
1547
1548 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1549 static void VM_CL_te_superspikequad (void)
1550 {
1551         float           *pos;
1552         vec3_t          pos2;
1553         int                     rnd;
1554         VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1555
1556         pos = PRVM_G_VECTOR(OFS_PARM0);
1557         CL_FindNonSolidLocation(pos, pos2, 4);
1558         CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1559         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1560         else
1561         {
1562                 rnd = rand() & 3;
1563                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1564                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1565                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1566         }
1567 }
1568
1569 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1570 static void VM_CL_te_explosionquad (void)
1571 {
1572         float           *pos;
1573         vec3_t          pos2;
1574         VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1575
1576         pos = PRVM_G_VECTOR(OFS_PARM0);
1577         CL_FindNonSolidLocation(pos, pos2, 10);
1578         CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1579         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1580 }
1581
1582 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1583 static void VM_CL_te_smallflash (void)
1584 {
1585         float           *pos;
1586         vec3_t          pos2;
1587         VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1588
1589         pos = PRVM_G_VECTOR(OFS_PARM0);
1590         CL_FindNonSolidLocation(pos, pos2, 10);
1591         CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1592 }
1593
1594 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1595 static void VM_CL_te_customflash (void)
1596 {
1597         float           *pos;
1598         vec3_t          pos2;
1599         matrix4x4_t     tempmatrix;
1600         VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1601
1602         pos = PRVM_G_VECTOR(OFS_PARM0);
1603         CL_FindNonSolidLocation(pos, pos2, 4);
1604         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1605         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);
1606 }
1607
1608 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1609 static void VM_CL_te_gunshot (void)
1610 {
1611         float           *pos;
1612         vec3_t          pos2;
1613         int                     rnd;
1614         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1615
1616         pos = PRVM_G_VECTOR(OFS_PARM0);
1617         CL_FindNonSolidLocation(pos, pos2, 4);
1618         CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1619         if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1620         {
1621                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1622                 else
1623                 {
1624                         rnd = rand() & 3;
1625                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1626                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1627                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1628                 }
1629         }
1630 }
1631
1632 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1633 static void VM_CL_te_spike (void)
1634 {
1635         float           *pos;
1636         vec3_t          pos2;
1637         int                     rnd;
1638         VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1639
1640         pos = PRVM_G_VECTOR(OFS_PARM0);
1641         CL_FindNonSolidLocation(pos, pos2, 4);
1642         CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1643         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1644         else
1645         {
1646                 rnd = rand() & 3;
1647                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1648                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1649                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1650         }
1651 }
1652
1653 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1654 static void VM_CL_te_superspike (void)
1655 {
1656         float           *pos;
1657         vec3_t          pos2;
1658         int                     rnd;
1659         VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1660
1661         pos = PRVM_G_VECTOR(OFS_PARM0);
1662         CL_FindNonSolidLocation(pos, pos2, 4);
1663         CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1664         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1665         else
1666         {
1667                 rnd = rand() & 3;
1668                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1669                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1670                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1671         }
1672 }
1673
1674 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1675 static void VM_CL_te_explosion (void)
1676 {
1677         float           *pos;
1678         vec3_t          pos2;
1679         VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1680
1681         pos = PRVM_G_VECTOR(OFS_PARM0);
1682         CL_FindNonSolidLocation(pos, pos2, 10);
1683         CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1684         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1685 }
1686
1687 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1688 static void VM_CL_te_tarexplosion (void)
1689 {
1690         float           *pos;
1691         vec3_t          pos2;
1692         VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1693
1694         pos = PRVM_G_VECTOR(OFS_PARM0);
1695         CL_FindNonSolidLocation(pos, pos2, 10);
1696         CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1697         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1698 }
1699
1700 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1701 static void VM_CL_te_wizspike (void)
1702 {
1703         float           *pos;
1704         vec3_t          pos2;
1705         VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1706
1707         pos = PRVM_G_VECTOR(OFS_PARM0);
1708         CL_FindNonSolidLocation(pos, pos2, 4);
1709         CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1710         S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1711 }
1712
1713 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1714 static void VM_CL_te_knightspike (void)
1715 {
1716         float           *pos;
1717         vec3_t          pos2;
1718         VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1719
1720         pos = PRVM_G_VECTOR(OFS_PARM0);
1721         CL_FindNonSolidLocation(pos, pos2, 4);
1722         CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1723         S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1724 }
1725
1726 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1727 static void VM_CL_te_lavasplash (void)
1728 {
1729         VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1730         CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1731 }
1732
1733 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1734 static void VM_CL_te_teleport (void)
1735 {
1736         VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1737         CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1738 }
1739
1740 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1741 static void VM_CL_te_explosion2 (void)
1742 {
1743         float           *pos;
1744         vec3_t          pos2, color;
1745         matrix4x4_t     tempmatrix;
1746         int                     colorStart, colorLength;
1747         unsigned char           *tempcolor;
1748         VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1749
1750         pos = PRVM_G_VECTOR(OFS_PARM0);
1751         colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1752         colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1753         CL_FindNonSolidLocation(pos, pos2, 10);
1754         CL_ParticleExplosion2(pos2, colorStart, colorLength);
1755         tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
1756         color[0] = tempcolor[0] * (2.0f / 255.0f);
1757         color[1] = tempcolor[1] * (2.0f / 255.0f);
1758         color[2] = tempcolor[2] * (2.0f / 255.0f);
1759         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1760         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);
1761         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1762 }
1763
1764
1765 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1766 static void VM_CL_te_lightning1 (void)
1767 {
1768         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1769         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1770 }
1771
1772 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1773 static void VM_CL_te_lightning2 (void)
1774 {
1775         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1776         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1777 }
1778
1779 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1780 static void VM_CL_te_lightning3 (void)
1781 {
1782         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1783         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1784 }
1785
1786 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1787 static void VM_CL_te_beam (void)
1788 {
1789         VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1790         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1791 }
1792
1793 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1794 static void VM_CL_te_plasmaburn (void)
1795 {
1796         float           *pos;
1797         vec3_t          pos2;
1798         VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1799
1800         pos = PRVM_G_VECTOR(OFS_PARM0);
1801         CL_FindNonSolidLocation(pos, pos2, 4);
1802         CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1803 }
1804
1805 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1806 static void VM_CL_te_flamejet (void)
1807 {
1808         float *pos;
1809         vec3_t pos2;
1810         VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1811         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1812                 return;
1813         pos = PRVM_G_VECTOR(OFS_PARM0);
1814         CL_FindNonSolidLocation(pos, pos2, 4);
1815         CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1816 }
1817
1818
1819 //====================================================================
1820 //DP_QC_GETSURFACE
1821
1822 extern void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1823
1824 static msurface_t *cl_getsurface(dp_model_t *model, int surfacenum)
1825 {
1826         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1827                 return NULL;
1828         return model->data_surfaces + surfacenum + model->firstmodelsurface;
1829 }
1830
1831 // #434 float(entity e, float s) getsurfacenumpoints
1832 static void VM_CL_getsurfacenumpoints(void)
1833 {
1834         dp_model_t *model;
1835         msurface_t *surface;
1836         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1837         // return 0 if no such surface
1838         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1839         {
1840                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1841                 return;
1842         }
1843
1844         // note: this (incorrectly) assumes it is a simple polygon
1845         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1846 }
1847
1848 // #435 vector(entity e, float s, float n) getsurfacepoint
1849 static void VM_CL_getsurfacepoint(void)
1850 {
1851         prvm_edict_t *ed;
1852         dp_model_t *model;
1853         msurface_t *surface;
1854         int pointnum;
1855         VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1856         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1857         ed = PRVM_G_EDICT(OFS_PARM0);
1858         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1859                 return;
1860         // note: this (incorrectly) assumes it is a simple polygon
1861         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1862         if (pointnum < 0 || pointnum >= surface->num_vertices)
1863                 return;
1864         // FIXME: implement rotation/scaling
1865         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1866 }
1867 //PF_getsurfacepointattribute,     // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
1868 // float SPA_POSITION = 0;
1869 // float SPA_S_AXIS = 1;
1870 // float SPA_T_AXIS = 2;
1871 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1872 // float SPA_TEXCOORDS0 = 4;
1873 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1874 // float SPA_LIGHTMAP0_COLOR = 6;
1875 // TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black]
1876 static void VM_CL_getsurfacepointattribute(void)
1877 {
1878         prvm_edict_t *ed;
1879         dp_model_t *model;
1880         msurface_t *surface;
1881         int pointnum;
1882         int attributetype;
1883
1884         VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints);
1885         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1886         ed = PRVM_G_EDICT(OFS_PARM0);
1887         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1888                 return;
1889         // note: this (incorrectly) assumes it is a simple polygon
1890         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1891         if (pointnum < 0 || pointnum >= surface->num_vertices)
1892                 return;
1893
1894         // FIXME: implement rotation/scaling
1895         attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
1896
1897         switch( attributetype ) {
1898                 // float SPA_POSITION = 0;
1899                 case 0:
1900                         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1901                         break;
1902                 // float SPA_S_AXIS = 1;
1903                 case 1:
1904                         VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1905                         break;
1906                 // float SPA_T_AXIS = 2;
1907                 case 2:
1908                         VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1909                         break;
1910                 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1911                 case 3:
1912                         VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1913                         break;
1914                 // float SPA_TEXCOORDS0 = 4;
1915                 case 4: {
1916                         float *ret = PRVM_G_VECTOR(OFS_RETURN);
1917                         float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
1918                         ret[0] = texcoord[0];
1919                         ret[1] = texcoord[1];
1920                         ret[2] = 0.0f;
1921                         break;
1922                 }
1923                 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1924                 case 5: {
1925                         float *ret = PRVM_G_VECTOR(OFS_RETURN);
1926                         float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
1927                         ret[0] = texcoord[0];
1928                         ret[1] = texcoord[1];
1929                         ret[2] = 0.0f;
1930                         break;
1931                 }
1932                 // float SPA_LIGHTMAP0_COLOR = 6;
1933                 case 6:
1934                         // ignore alpha for now..
1935                         VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
1936                         break;
1937                 default:
1938                         VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
1939                         break;
1940         }
1941 }
1942 // #436 vector(entity e, float s) getsurfacenormal
1943 static void VM_CL_getsurfacenormal(void)
1944 {
1945         dp_model_t *model;
1946         msurface_t *surface;
1947         vec3_t normal;
1948         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1949         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1950         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1951                 return;
1952         // FIXME: implement rotation/scaling
1953         // note: this (incorrectly) assumes it is a simple polygon
1954         // note: this only returns the first triangle, so it doesn't work very
1955         // well for curved surfaces or arbitrary meshes
1956         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);
1957         VectorNormalize(normal);
1958         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1959 }
1960
1961 // #437 string(entity e, float s) getsurfacetexture
1962 static void VM_CL_getsurfacetexture(void)
1963 {
1964         dp_model_t *model;
1965         msurface_t *surface;
1966         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1967         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1968         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1969                 return;
1970         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1971 }
1972
1973 // #438 float(entity e, vector p) getsurfacenearpoint
1974 static void VM_CL_getsurfacenearpoint(void)
1975 {
1976         int surfacenum, best;
1977         vec3_t clipped, p;
1978         vec_t dist, bestdist;
1979         prvm_edict_t *ed;
1980         dp_model_t *model = NULL;
1981         msurface_t *surface;
1982         vec_t *point;
1983         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1984         PRVM_G_FLOAT(OFS_RETURN) = -1;
1985         ed = PRVM_G_EDICT(OFS_PARM0);
1986         if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1987                 return;
1988
1989         // FIXME: implement rotation/scaling
1990         point = PRVM_G_VECTOR(OFS_PARM1);
1991         VectorSubtract(point, ed->fields.client->origin, p);
1992         best = -1;
1993         bestdist = 1000000000;
1994         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1995         {
1996                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1997                 // first see if the nearest point on the surface's box is closer than the previous match
1998                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1999                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2000                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2001                 dist = VectorLength2(clipped);
2002                 if (dist < bestdist)
2003                 {
2004                         // it is, check the nearest point on the actual geometry
2005                         clippointtosurface(model, surface, p, clipped);
2006                         VectorSubtract(clipped, p, clipped);
2007                         dist += VectorLength2(clipped);
2008                         if (dist < bestdist)
2009                         {
2010                                 // that's closer too, store it as the best match
2011                                 best = surfacenum;
2012                                 bestdist = dist;
2013                         }
2014                 }
2015         }
2016         PRVM_G_FLOAT(OFS_RETURN) = best;
2017 }
2018
2019 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
2020 static void VM_CL_getsurfaceclippedpoint(void)
2021 {
2022         prvm_edict_t *ed;
2023         dp_model_t *model;
2024         msurface_t *surface;
2025         vec3_t p, out;
2026         VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
2027         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2028         ed = PRVM_G_EDICT(OFS_PARM0);
2029         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2030                 return;
2031         // FIXME: implement rotation/scaling
2032         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
2033         clippointtosurface(model, surface, p, out);
2034         // FIXME: implement rotation/scaling
2035         VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
2036 }
2037
2038 // #443 void(entity e, entity tagentity, string tagname) setattachment
2039 void VM_CL_setattachment (void)
2040 {
2041         prvm_edict_t *e;
2042         prvm_edict_t *tagentity;
2043         const char *tagname;
2044         prvm_eval_t *v;
2045         int modelindex;
2046         dp_model_t *model;
2047         VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
2048
2049         e = PRVM_G_EDICT(OFS_PARM0);
2050         tagentity = PRVM_G_EDICT(OFS_PARM1);
2051         tagname = PRVM_G_STRING(OFS_PARM2);
2052
2053         if (e == prog->edicts)
2054         {
2055                 VM_Warning("setattachment: can not modify world entity\n");
2056                 return;
2057         }
2058         if (e->priv.server->free)
2059         {
2060                 VM_Warning("setattachment: can not modify free entity\n");
2061                 return;
2062         }
2063
2064         if (tagentity == NULL)
2065                 tagentity = prog->edicts;
2066
2067         v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2068         if (v)
2069                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2070
2071         v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2072         if (v)
2073                 v->_float = 0;
2074         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2075         {
2076                 modelindex = (int)tagentity->fields.client->modelindex;
2077                 model = CL_GetModelByIndex(modelindex);
2078                 if (model)
2079                 {
2080                         v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
2081                         if (v->_float == 0)
2082                                 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);
2083                 }
2084                 else
2085                         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));
2086         }
2087 }
2088
2089 /////////////////////////////////////////
2090 // DP_MD3_TAGINFO extension coded by VorteX
2091
2092 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
2093 {
2094         dp_model_t *model = CL_GetModelFromEdict(e);
2095         if (model)
2096                 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
2097         else
2098                 return -1;
2099 };
2100
2101 // Warnings/errors code:
2102 // 0 - normal (everything all-right)
2103 // 1 - world entity
2104 // 2 - free entity
2105 // 3 - null or non-precached model
2106 // 4 - no tags with requested index
2107 // 5 - runaway loop at attachment chain
2108 extern cvar_t cl_bob;
2109 extern cvar_t cl_bobcycle;
2110 extern cvar_t cl_bobup;
2111 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2112 {
2113         prvm_eval_t *val;
2114         int reqframe, attachloop;
2115         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2116         prvm_edict_t *attachent;
2117         dp_model_t *model;
2118         float scale;
2119
2120         *out = identitymatrix; // warnings and errors return identical matrix
2121
2122         if (ent == prog->edicts)
2123                 return 1;
2124         if (ent->priv.server->free)
2125                 return 2;
2126
2127         model = CL_GetModelFromEdict(ent);
2128
2129         if(!model)
2130                 return 3;
2131
2132         if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
2133                 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
2134         else
2135                 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2136
2137         // get initial tag matrix
2138         if (tagindex)
2139         {
2140                 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2141                 if (ret)
2142                         return ret;
2143         }
2144         else
2145                 tagmatrix = identitymatrix;
2146
2147         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2148         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2149                 attachloop = 0;
2150                 do
2151                 {
2152                         attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2153                         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
2154
2155                         model = CL_GetModelFromEdict(attachent);
2156
2157                         if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
2158                                 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
2159                         else
2160                                 attachmatrix = identitymatrix;
2161
2162                         // apply transformation by child entity matrix
2163                         scale = 1;
2164                         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2165                         if (val && val->_float != 0)
2166                                 scale = val->_float;
2167                         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);
2168                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2169                         Matrix4x4_Copy(&tagmatrix, out);
2170
2171                         // finally transformate by matrix of tag on parent entity
2172                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2173                         Matrix4x4_Copy(&tagmatrix, out);
2174
2175                         ent = attachent;
2176                         attachloop += 1;
2177                         if (attachloop > 255) // prevent runaway looping
2178                                 return 5;
2179                 }
2180                 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
2181         }
2182
2183         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2184         scale = 1;
2185         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2186         if (val && val->_float != 0)
2187                 scale = val->_float;
2188         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2189         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);
2190         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2191
2192         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
2193         {// RENDER_VIEWMODEL magic
2194                 Matrix4x4_Copy(&tagmatrix, out);
2195
2196                 scale = 1;
2197                 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2198                 if (val && val->_float != 0)
2199                         scale = val->_float;
2200
2201                 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);
2202                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2203
2204                 /*
2205                 // Cl_bob, ported from rendering code
2206                 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2207                 {
2208                         double bob, cycle;
2209                         // LordHavoc: this code is *weird*, but not replacable (I think it
2210                         // should be done in QC on the server, but oh well, quake is quake)
2211                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2212                         // degrees (which allows lengthening or squishing the peak or valley)
2213                         cycle = cl.time/cl_bobcycle.value;
2214                         cycle -= (int)cycle;
2215                         if (cycle < cl_bobup.value)
2216                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2217                         else
2218                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2219                         // bob is proportional to velocity in the xy plane
2220                         // (don't count Z, or jumping messes it up)
2221                         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;
2222                         bob = bob*0.3 + bob*0.7*cycle;
2223                         Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2224                 }
2225                 */
2226         }
2227         return 0;
2228 }
2229
2230 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2231 void VM_CL_gettagindex (void)
2232 {
2233         prvm_edict_t *ent;
2234         const char *tag_name;
2235         int modelindex, tag_index;
2236
2237         VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2238
2239         ent = PRVM_G_EDICT(OFS_PARM0);
2240         tag_name = PRVM_G_STRING(OFS_PARM1);
2241         if (ent == prog->edicts)
2242         {
2243                 VM_Warning("gettagindex: can't affect world entity\n");
2244                 return;
2245         }
2246         if (ent->priv.server->free)
2247         {
2248                 VM_Warning("gettagindex: can't affect free entity\n");
2249                 return;
2250         }
2251
2252         modelindex = (int)ent->fields.client->modelindex;
2253         tag_index = 0;
2254         if (modelindex >= MAX_MODELS || (modelindex <= -MAX_MODELS /* client models */))
2255                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2256         else
2257         {
2258                 tag_index = CL_GetTagIndex(ent, tag_name);
2259                 if (tag_index == 0)
2260                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2261         }
2262         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2263 }
2264
2265 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2266 void VM_CL_gettaginfo (void)
2267 {
2268         prvm_edict_t *e;
2269         int tagindex;
2270         matrix4x4_t tag_matrix;
2271         int returncode;
2272
2273         VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2274
2275         e = PRVM_G_EDICT(OFS_PARM0);
2276         tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2277         returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2278         Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2279
2280         switch(returncode)
2281         {
2282                 case 1:
2283                         VM_Warning("gettagindex: can't affect world entity\n");
2284                         break;
2285                 case 2:
2286                         VM_Warning("gettagindex: can't affect free entity\n");
2287                         break;
2288                 case 3:
2289                         Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2290                         break;
2291                 case 4:
2292                         Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2293                         break;
2294                 case 5:
2295                         Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2296                         break;
2297         }
2298 }
2299
2300 //============================================================================
2301
2302 //====================
2303 //QC POLYGON functions
2304 //====================
2305
2306 #define VMPOLYGONS_MAXPOINTS 64
2307
2308 typedef struct vmpolygons_triangle_s
2309 {
2310         rtexture_t              *texture;
2311         int                             drawflag;
2312         unsigned short  elements[3];
2313 }vmpolygons_triangle_t;
2314
2315 typedef struct vmpolygons_s
2316 {
2317         mempool_t               *pool;
2318         qboolean                initialized;
2319
2320         int                             max_vertices;
2321         int                             num_vertices;
2322         float                   *data_vertex3f;
2323         float                   *data_color4f;
2324         float                   *data_texcoord2f;
2325
2326         int                             max_triangles;
2327         int                             num_triangles;
2328         vmpolygons_triangle_t *data_triangles;
2329         unsigned short  *data_sortedelement3s;
2330
2331         qboolean                begin_active;
2332         rtexture_t              *begin_texture;
2333         int                             begin_drawflag;
2334         int                             begin_vertices;
2335         float                   begin_vertex[VMPOLYGONS_MAXPOINTS][3];
2336         float                   begin_color[VMPOLYGONS_MAXPOINTS][4];
2337         float                   begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
2338 } vmpolygons_t;
2339
2340 // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
2341 vmpolygons_t vmpolygons[PRVM_MAXPROGS];
2342
2343 //#304 void() renderscene (EXT_CSQC)
2344 // moved that here to reset the polygons,
2345 // resetting them earlier causes R_Mesh_Draw to be called with numvertices = 0
2346 // --blub
2347 void VM_CL_R_RenderScene (void)
2348 {
2349         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2350         VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
2351         // we need to update any RENDER_VIEWMODEL entities at this point because
2352         // csqc supplies its own view matrix
2353         CL_UpdateViewEntities();
2354         // now draw stuff!
2355         R_RenderView();
2356
2357         polys->num_vertices = polys->num_triangles = 0;
2358 }
2359
2360 static void VM_ResizePolygons(vmpolygons_t *polys)
2361 {
2362         float *oldvertex3f = polys->data_vertex3f;
2363         float *oldcolor4f = polys->data_color4f;
2364         float *oldtexcoord2f = polys->data_texcoord2f;
2365         vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
2366         unsigned short *oldsortedelement3s = polys->data_sortedelement3s;
2367         polys->max_vertices = min(polys->max_triangles*3, 65536);
2368         polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
2369         polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
2370         polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
2371         polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
2372         polys->data_sortedelement3s = (unsigned short *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(unsigned short[3]));
2373         if (polys->num_vertices)
2374         {
2375                 memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
2376                 memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
2377                 memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
2378         }
2379         if (polys->num_triangles)
2380         {
2381                 memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
2382                 memcpy(polys->data_sortedelement3s, oldsortedelement3s, polys->num_triangles*sizeof(unsigned short[3]));
2383         }
2384         if (oldvertex3f)
2385                 Mem_Free(oldvertex3f);
2386         if (oldcolor4f)
2387                 Mem_Free(oldcolor4f);
2388         if (oldtexcoord2f)
2389                 Mem_Free(oldtexcoord2f);
2390         if (oldtriangles)
2391                 Mem_Free(oldtriangles);
2392         if (oldsortedelement3s)
2393                 Mem_Free(oldsortedelement3s);
2394 }
2395
2396 static void VM_InitPolygons (vmpolygons_t* polys)
2397 {
2398         memset(polys, 0, sizeof(*polys));
2399         polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
2400         polys->max_triangles = 1024;
2401         VM_ResizePolygons(polys);
2402         polys->initialized = true;
2403 }
2404
2405 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2406 {
2407         int surfacelistindex;
2408         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2409         R_Mesh_Matrix(&identitymatrix);
2410         GL_CullFace(GL_NONE);
2411         R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
2412         R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
2413         R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
2414         R_SetupGenericShader(true);
2415         for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
2416         {
2417                 int numtriangles = 0;
2418                 rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
2419                 int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
2420                 if(drawflag == DRAWFLAG_ADDITIVE)
2421                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2422                 else if(drawflag == DRAWFLAG_MODULATE)
2423                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2424                 else if(drawflag == DRAWFLAG_2XMODULATE)
2425                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2426                 else
2427                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2428                 R_Mesh_TexBind(0, R_GetTexture(tex));
2429                 numtriangles = 0;
2430                 for (;surfacelistindex < numsurfaces;surfacelistindex++)
2431                 {
2432                         if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag)
2433                                 break;
2434                         VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles);
2435                         numtriangles++;
2436                 }
2437                 R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, polys->data_sortedelement3s, 0, 0);
2438         }
2439 }
2440
2441 void VMPolygons_Store(vmpolygons_t *polys)
2442 {
2443         if (r_refdef.draw2dstage)
2444         {
2445                 // draw the polygon as 2D immediately
2446                 drawqueuemesh_t mesh;
2447                 mesh.texture = polys->begin_texture;
2448                 mesh.num_vertices = polys->begin_vertices;
2449                 mesh.num_triangles = polys->begin_vertices-2;
2450                 mesh.data_element3s = polygonelements;
2451                 mesh.data_vertex3f = polys->begin_vertex[0];
2452                 mesh.data_color4f = polys->begin_color[0];
2453                 mesh.data_texcoord2f = polys->begin_texcoord[0];
2454                 DrawQ_Mesh(&mesh, polys->begin_drawflag);
2455         }
2456         else
2457         {
2458                 // queue the polygon as 3D for sorted transparent rendering later
2459                 int i;
2460                 if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2)
2461                 {
2462                         polys->max_triangles *= 2;
2463                         VM_ResizePolygons(polys);
2464                 }
2465                 if (polys->num_vertices + polys->begin_vertices <= polys->max_vertices)
2466                 {
2467                         // needle in a haystack!
2468                         // polys->num_vertices was used for copying where we actually want to copy begin_vertices
2469                         // that also caused it to not render the first polygon that is added
2470                         // --blub
2471                         memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->begin_vertices * sizeof(float[3]));
2472                         memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->begin_vertices * sizeof(float[4]));
2473                         memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->begin_vertices * sizeof(float[2]));
2474                         for (i = 0;i < polys->begin_vertices-2;i++)
2475                         {
2476                                 polys->data_triangles[polys->num_triangles].texture = polys->begin_texture;
2477                                 polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag;
2478                                 polys->data_triangles[polys->num_triangles].elements[0] = polys->num_vertices;
2479                                 polys->data_triangles[polys->num_triangles].elements[1] = polys->num_vertices + i+1;
2480                                 polys->data_triangles[polys->num_triangles].elements[2] = polys->num_vertices + i+2;
2481                                 polys->num_triangles++;
2482                         }
2483                         polys->num_vertices += polys->begin_vertices;
2484                 }
2485         }
2486         polys->begin_active = false;
2487 }
2488
2489 // TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
2490 // LordHavoc: agreed, this is a mess
2491 void VM_CL_AddPolygonsToMeshQueue (void)
2492 {
2493         int i;
2494         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2495         vec3_t center;
2496
2497         // only add polygons of the currently active prog to the queue - if there is none, we're done
2498         if( !prog )
2499                 return;
2500
2501         if (!polys->num_triangles)
2502                 return;
2503
2504         for (i = 0;i < polys->num_triangles;i++)
2505         {
2506                 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);
2507                 R_MeshQueue_AddTransparent(center, VM_DrawPolygonCallback, NULL, i, NULL);
2508         }
2509
2510         /*polys->num_triangles = 0; // now done after rendering the scene,
2511           polys->num_vertices = 0;  // otherwise it's not rendered at all and prints an error message --blub */
2512 }
2513
2514 //void(string texturename, float flag) R_BeginPolygon
2515 void VM_CL_R_PolygonBegin (void)
2516 {
2517         const char              *picname;
2518         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2519
2520         VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
2521
2522         if (!polys->initialized)
2523                 VM_InitPolygons(polys);
2524         if (polys->begin_active)
2525         {
2526                 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
2527                 return;
2528         }
2529         picname = PRVM_G_STRING(OFS_PARM0);
2530         polys->begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white;
2531         polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
2532         polys->begin_vertices = 0;
2533         polys->begin_active = true;
2534 }
2535
2536 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2537 void VM_CL_R_PolygonVertex (void)
2538 {
2539         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2540
2541         VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2542
2543         if (!polys->begin_active)
2544         {
2545                 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2546                 return;
2547         }
2548
2549         if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
2550         {
2551                 VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2552                 return;
2553         }
2554
2555         polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0];
2556         polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1];
2557         polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2];
2558         polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0];
2559         polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1];
2560         polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0];
2561         polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1];
2562         polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2];
2563         polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3);
2564         polys->begin_vertices++;
2565 }
2566
2567 //void() R_EndPolygon
2568 void VM_CL_R_PolygonEnd (void)
2569 {
2570         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2571
2572         VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2573         if (!polys->begin_active)
2574         {
2575                 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2576                 return;
2577         }
2578         polys->begin_active = false;
2579         if (polys->begin_vertices >= 3)
2580                 VMPolygons_Store(polys);
2581         else
2582                 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
2583 }
2584
2585 static vmpolygons_t debugPolys;
2586
2587 void Debug_PolygonBegin(const char *picname, int drawflag)
2588 {
2589         if(!debugPolys.initialized)
2590                 VM_InitPolygons(&debugPolys);
2591         if(debugPolys.begin_active)
2592         {
2593                 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2594                 return;
2595         }
2596         debugPolys.begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white;
2597         debugPolys.begin_drawflag = drawflag;
2598         debugPolys.begin_vertices = 0;
2599         debugPolys.begin_active = true;
2600 }
2601
2602 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2603 {
2604         if(!debugPolys.begin_active)
2605         {
2606                 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2607                 return;
2608         }
2609
2610         if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS)
2611         {
2612                 Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2613                 return;
2614         }
2615
2616         debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x;
2617         debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y;
2618         debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z;
2619         debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s;
2620         debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t;
2621         debugPolys.begin_color[debugPolys.begin_vertices][0] = r;
2622         debugPolys.begin_color[debugPolys.begin_vertices][1] = g;
2623         debugPolys.begin_color[debugPolys.begin_vertices][2] = b;
2624         debugPolys.begin_color[debugPolys.begin_vertices][3] = a;
2625         debugPolys.begin_vertices++;
2626 }
2627
2628 void Debug_PolygonEnd(void)
2629 {
2630         if (!debugPolys.begin_active)
2631         {
2632                 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2633                 return;
2634         }
2635         debugPolys.begin_active = false;
2636         if (debugPolys.begin_vertices >= 3)
2637                 VMPolygons_Store(&debugPolys);
2638         else
2639                 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
2640 }
2641
2642 /*
2643 =============
2644 CL_CheckBottom
2645
2646 Returns false if any part of the bottom of the entity is off an edge that
2647 is not a staircase.
2648
2649 =============
2650 */
2651 qboolean CL_CheckBottom (prvm_edict_t *ent)
2652 {
2653         vec3_t  mins, maxs, start, stop;
2654         trace_t trace;
2655         int             x, y;
2656         float   mid, bottom;
2657
2658         VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2659         VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2660
2661 // if all of the points under the corners are solid world, don't bother
2662 // with the tougher checks
2663 // the corners must be within 16 of the midpoint
2664         start[2] = mins[2] - 1;
2665         for     (x=0 ; x<=1 ; x++)
2666                 for     (y=0 ; y<=1 ; y++)
2667                 {
2668                         start[0] = x ? maxs[0] : mins[0];
2669                         start[1] = y ? maxs[1] : mins[1];
2670                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2671                                 goto realcheck;
2672                 }
2673
2674         return true;            // we got out easy
2675
2676 realcheck:
2677 //
2678 // check it for real...
2679 //
2680         start[2] = mins[2];
2681
2682 // the midpoint must be within 16 of the bottom
2683         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2684         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2685         stop[2] = start[2] - 2*sv_stepheight.value;
2686         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2687
2688         if (trace.fraction == 1.0)
2689                 return false;
2690         mid = bottom = trace.endpos[2];
2691
2692 // the corners must be within 16 of the midpoint
2693         for     (x=0 ; x<=1 ; x++)
2694                 for     (y=0 ; y<=1 ; y++)
2695                 {
2696                         start[0] = stop[0] = x ? maxs[0] : mins[0];
2697                         start[1] = stop[1] = y ? maxs[1] : mins[1];
2698
2699                         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2700
2701                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2702                                 bottom = trace.endpos[2];
2703                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2704                                 return false;
2705                 }
2706
2707         return true;
2708 }
2709
2710 /*
2711 =============
2712 CL_movestep
2713
2714 Called by monster program code.
2715 The move will be adjusted for slopes and stairs, but if the move isn't
2716 possible, no move is done and false is returned
2717 =============
2718 */
2719 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2720 {
2721         float           dz;
2722         vec3_t          oldorg, neworg, end, traceendpos;
2723         trace_t         trace;
2724         int                     i;
2725         prvm_edict_t            *enemy;
2726         prvm_eval_t     *val;
2727
2728 // try the move
2729         VectorCopy (ent->fields.client->origin, oldorg);
2730         VectorAdd (ent->fields.client->origin, move, neworg);
2731
2732 // flying monsters don't step up
2733         if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2734         {
2735         // try one move with vertical motion, then one without
2736                 for (i=0 ; i<2 ; i++)
2737                 {
2738                         VectorAdd (ent->fields.client->origin, move, neworg);
2739                         enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2740                         if (i == 0 && enemy != prog->edicts)
2741                         {
2742                                 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2743                                 if (dz > 40)
2744                                         neworg[2] -= 8;
2745                                 if (dz < 30)
2746                                         neworg[2] += 8;
2747                         }
2748                         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);
2749                         if (settrace)
2750                                 VM_SetTraceGlobals(&trace);
2751
2752                         if (trace.fraction == 1)
2753                         {
2754                                 VectorCopy(trace.endpos, traceendpos);
2755                                 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2756                                         return false;   // swim monster left water
2757
2758                                 VectorCopy (traceendpos, ent->fields.client->origin);
2759                                 if (relink)
2760                                         CL_LinkEdict(ent);
2761                                 return true;
2762                         }
2763
2764                         if (enemy == prog->edicts)
2765                                 break;
2766                 }
2767
2768                 return false;
2769         }
2770
2771 // push down from a step height above the wished position
2772         neworg[2] += sv_stepheight.value;
2773         VectorCopy (neworg, end);
2774         end[2] -= sv_stepheight.value*2;
2775
2776         trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2777         if (settrace)
2778                 VM_SetTraceGlobals(&trace);
2779
2780         if (trace.startsolid)
2781         {
2782                 neworg[2] -= sv_stepheight.value;
2783                 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2784                 if (settrace)
2785                         VM_SetTraceGlobals(&trace);
2786                 if (trace.startsolid)
2787                         return false;
2788         }
2789         if (trace.fraction == 1)
2790         {
2791         // if monster had the ground pulled out, go ahead and fall
2792                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2793                 {
2794                         VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2795                         if (relink)
2796                                 CL_LinkEdict(ent);
2797                         ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2798                         return true;
2799                 }
2800
2801                 return false;           // walked off an edge
2802         }
2803
2804 // check point traces down for dangling corners
2805         VectorCopy (trace.endpos, ent->fields.client->origin);
2806
2807         if (!CL_CheckBottom (ent))
2808         {
2809                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2810                 {       // entity had floor mostly pulled out from underneath it
2811                         // and is trying to correct
2812                         if (relink)
2813                                 CL_LinkEdict(ent);
2814                         return true;
2815                 }
2816                 VectorCopy (oldorg, ent->fields.client->origin);
2817                 return false;
2818         }
2819
2820         if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2821                 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2822
2823         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2824                 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2825
2826 // the move is ok
2827         if (relink)
2828                 CL_LinkEdict(ent);
2829         return true;
2830 }
2831
2832 /*
2833 ===============
2834 VM_CL_walkmove
2835
2836 float(float yaw, float dist[, settrace]) walkmove
2837 ===============
2838 */
2839 static void VM_CL_walkmove (void)
2840 {
2841         prvm_edict_t    *ent;
2842         float   yaw, dist;
2843         vec3_t  move;
2844         mfunction_t     *oldf;
2845         int     oldself;
2846         qboolean        settrace;
2847
2848         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2849
2850         // assume failure if it returns early
2851         PRVM_G_FLOAT(OFS_RETURN) = 0;
2852
2853         ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2854         if (ent == prog->edicts)
2855         {
2856                 VM_Warning("walkmove: can not modify world entity\n");
2857                 return;
2858         }
2859         if (ent->priv.server->free)
2860         {
2861                 VM_Warning("walkmove: can not modify free entity\n");
2862                 return;
2863         }
2864         yaw = PRVM_G_FLOAT(OFS_PARM0);
2865         dist = PRVM_G_FLOAT(OFS_PARM1);
2866         settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2867
2868         if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2869                 return;
2870
2871         yaw = yaw*M_PI*2 / 360;
2872
2873         move[0] = cos(yaw)*dist;
2874         move[1] = sin(yaw)*dist;
2875         move[2] = 0;
2876
2877 // save program state, because CL_movestep may call other progs
2878         oldf = prog->xfunction;
2879         oldself = prog->globals.client->self;
2880
2881         PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2882
2883
2884 // restore program state
2885         prog->xfunction = oldf;
2886         prog->globals.client->self = oldself;
2887 }
2888
2889 /*
2890 ===============
2891 VM_CL_serverkey
2892
2893 string(string key) serverkey
2894 ===============
2895 */
2896 void VM_CL_serverkey(void)
2897 {
2898         char string[VM_STRINGTEMP_LENGTH];
2899         VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2900         InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2901         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2902 }
2903
2904 //============================================================================
2905
2906 // To create a almost working builtin file from this replace:
2907 // "^NULL.*" with ""
2908 // "^{.*//.*}:Wh\(.*\)" with "\1"
2909 // "\:" with "//"
2910 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
2911 // "\n\n+" with "\n\n"
2912
2913 prvm_builtin_t vm_cl_builtins[] = {
2914 NULL,                                                   // #0 NULL function (not callable) (QUAKE)
2915 VM_CL_makevectors,                              // #1 void(vector ang) makevectors (QUAKE)
2916 VM_CL_setorigin,                                // #2 void(entity e, vector o) setorigin (QUAKE)
2917 VM_CL_setmodel,                                 // #3 void(entity e, string m) setmodel (QUAKE)
2918 VM_CL_setsize,                                  // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2919 NULL,                                                   // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2920 VM_break,                                               // #6 void() break (QUAKE)
2921 VM_random,                                              // #7 float() random (QUAKE)
2922 VM_CL_sound,                                    // #8 void(entity e, float chan, string samp) sound (QUAKE)
2923 VM_normalize,                                   // #9 vector(vector v) normalize (QUAKE)
2924 VM_error,                                               // #10 void(string e) error (QUAKE)
2925 VM_objerror,                                    // #11 void(string e) objerror (QUAKE)
2926 VM_vlen,                                                // #12 float(vector v) vlen (QUAKE)
2927 VM_vectoyaw,                                    // #13 float(vector v) vectoyaw (QUAKE)
2928 VM_CL_spawn,                                    // #14 entity() spawn (QUAKE)
2929 VM_remove,                                              // #15 void(entity e) remove (QUAKE)
2930 VM_CL_traceline,                                // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
2931 NULL,                                                   // #17 entity() checkclient (QUAKE)
2932 VM_find,                                                // #18 entity(entity start, .string fld, string match) find (QUAKE)
2933 VM_precache_sound,                              // #19 void(string s) precache_sound (QUAKE)
2934 VM_CL_precache_model,                   // #20 void(string s) precache_model (QUAKE)
2935 NULL,                                                   // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2936 VM_CL_findradius,                               // #22 entity(vector org, float rad) findradius (QUAKE)
2937 NULL,                                                   // #23 void(string s, ...) bprint (QUAKE)
2938 NULL,                                                   // #24 void(entity client, string s, ...) sprint (QUAKE)
2939 VM_dprint,                                              // #25 void(string s, ...) dprint (QUAKE)
2940 VM_ftos,                                                // #26 string(float f) ftos (QUAKE)
2941 VM_vtos,                                                // #27 string(vector v) vtos (QUAKE)
2942 VM_coredump,                                    // #28 void() coredump (QUAKE)
2943 VM_traceon,                                             // #29 void() traceon (QUAKE)
2944 VM_traceoff,                                    // #30 void() traceoff (QUAKE)
2945 VM_eprint,                                              // #31 void(entity e) eprint (QUAKE)
2946 VM_CL_walkmove,                                 // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
2947 NULL,                                                   // #33 (QUAKE)
2948 VM_CL_droptofloor,                              // #34 float() droptofloor (QUAKE)
2949 VM_CL_lightstyle,                               // #35 void(float style, string value) lightstyle (QUAKE)
2950 VM_rint,                                                // #36 float(float v) rint (QUAKE)
2951 VM_floor,                                               // #37 float(float v) floor (QUAKE)
2952 VM_ceil,                                                // #38 float(float v) ceil (QUAKE)
2953 NULL,                                                   // #39 (QUAKE)
2954 VM_CL_checkbottom,                              // #40 float(entity e) checkbottom (QUAKE)
2955 VM_CL_pointcontents,                    // #41 float(vector v) pointcontents (QUAKE)
2956 NULL,                                                   // #42 (QUAKE)
2957 VM_fabs,                                                // #43 float(float f) fabs (QUAKE)
2958 NULL,                                                   // #44 vector(entity e, float speed) aim (QUAKE)
2959 VM_cvar,                                                // #45 float(string s) cvar (QUAKE)
2960 VM_localcmd,                                    // #46 void(string s) localcmd (QUAKE)
2961 VM_nextent,                                             // #47 entity(entity e) nextent (QUAKE)
2962 VM_CL_particle,                                 // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2963 VM_changeyaw,                                   // #49 void() ChangeYaw (QUAKE)
2964 NULL,                                                   // #50 (QUAKE)
2965 VM_vectoangles,                                 // #51 vector(vector v) vectoangles (QUAKE)
2966 NULL,                                                   // #52 void(float to, float f) WriteByte (QUAKE)
2967 NULL,                                                   // #53 void(float to, float f) WriteChar (QUAKE)
2968 NULL,                                                   // #54 void(float to, float f) WriteShort (QUAKE)
2969 NULL,                                                   // #55 void(float to, float f) WriteLong (QUAKE)
2970 NULL,                                                   // #56 void(float to, float f) WriteCoord (QUAKE)
2971 NULL,                                                   // #57 void(float to, float f) WriteAngle (QUAKE)
2972 NULL,                                                   // #58 void(float to, string s) WriteString (QUAKE)
2973 NULL,                                                   // #59 (QUAKE)
2974 VM_sin,                                                 // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2975 VM_cos,                                                 // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2976 VM_sqrt,                                                // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2977 VM_changepitch,                                 // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2978 VM_CL_tracetoss,                                // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2979 VM_etos,                                                // #65 string(entity ent) etos (DP_QC_ETOS)
2980 NULL,                                                   // #66 (QUAKE)
2981 NULL,                                                   // #67 void(float step) movetogoal (QUAKE)
2982 VM_precache_file,                               // #68 string(string s) precache_file (QUAKE)
2983 VM_CL_makestatic,                               // #69 void(entity e) makestatic (QUAKE)
2984 NULL,                                                   // #70 void(string s) changelevel (QUAKE)
2985 NULL,                                                   // #71 (QUAKE)
2986 VM_cvar_set,                                    // #72 void(string var, string val) cvar_set (QUAKE)
2987 NULL,                                                   // #73 void(entity client, strings) centerprint (QUAKE)
2988 VM_CL_ambientsound,                             // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2989 VM_CL_precache_model,                   // #75 string(string s) precache_model2 (QUAKE)
2990 VM_precache_sound,                              // #76 string(string s) precache_sound2 (QUAKE)
2991 VM_precache_file,                               // #77 string(string s) precache_file2 (QUAKE)
2992 NULL,                                                   // #78 void(entity e) setspawnparms (QUAKE)
2993 NULL,                                                   // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2994 NULL,                                                   // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2995 VM_stof,                                                // #81 float(string s) stof (FRIK_FILE)
2996 NULL,                                                   // #82 void(vector where, float set) multicast (QUAKEWORLD)
2997 NULL,                                                   // #83 (QUAKE)
2998 NULL,                                                   // #84 (QUAKE)
2999 NULL,                                                   // #85 (QUAKE)
3000 NULL,                                                   // #86 (QUAKE)
3001 NULL,                                                   // #87 (QUAKE)
3002 NULL,                                                   // #88 (QUAKE)
3003 NULL,                                                   // #89 (QUAKE)
3004 VM_CL_tracebox,                                 // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3005 VM_randomvec,                                   // #91 vector() randomvec (DP_QC_RANDOMVEC)
3006 VM_CL_getlight,                                 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3007 VM_registercvar,                                // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3008 VM_min,                                                 // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3009 VM_max,                                                 // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3010 VM_bound,                                               // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3011 VM_pow,                                                 // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3012 VM_findfloat,                                   // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3013 VM_checkextension,                              // #99 float(string s) checkextension (the basis of the extension system)
3014 // FrikaC and Telejano range #100-#199
3015 NULL,                                                   // #100
3016 NULL,                                                   // #101
3017 NULL,                                                   // #102
3018 NULL,                                                   // #103
3019 NULL,                                                   // #104
3020 NULL,                                                   // #105
3021 NULL,                                                   // #106
3022 NULL,                                                   // #107
3023 NULL,                                                   // #108
3024 NULL,                                                   // #109
3025 VM_fopen,                                               // #110 float(string filename, float mode) fopen (FRIK_FILE)
3026 VM_fclose,                                              // #111 void(float fhandle) fclose (FRIK_FILE)
3027 VM_fgets,                                               // #112 string(float fhandle) fgets (FRIK_FILE)
3028 VM_fputs,                                               // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3029 VM_strlen,                                              // #114 float(string s) strlen (FRIK_FILE)
3030 VM_strcat,                                              // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3031 VM_substring,                                   // #116 string(string s, float start, float length) substring (FRIK_FILE)
3032 VM_stov,                                                // #117 vector(string) stov (FRIK_FILE)
3033 VM_strzone,                                             // #118 string(string s) strzone (FRIK_FILE)
3034 VM_strunzone,                                   // #119 void(string s) strunzone (FRIK_FILE)
3035 NULL,                                                   // #120
3036 NULL,                                                   // #121
3037 NULL,                                                   // #122
3038 NULL,                                                   // #123
3039 NULL,                                                   // #124
3040 NULL,                                                   // #125
3041 NULL,                                                   // #126
3042 NULL,                                                   // #127
3043 NULL,                                                   // #128
3044 NULL,                                                   // #129
3045 NULL,                                                   // #130
3046 NULL,                                                   // #131
3047 NULL,                                                   // #132
3048 NULL,                                                   // #133
3049 NULL,                                                   // #134
3050 NULL,                                                   // #135
3051 NULL,                                                   // #136
3052 NULL,                                                   // #137
3053 NULL,                                                   // #138
3054 NULL,                                                   // #139
3055 NULL,                                                   // #140
3056 NULL,                                                   // #141
3057 NULL,                                                   // #142
3058 NULL,                                                   // #143
3059 NULL,                                                   // #144
3060 NULL,                                                   // #145
3061 NULL,                                                   // #146
3062 NULL,                                                   // #147
3063 NULL,                                                   // #148
3064 NULL,                                                   // #149
3065 NULL,                                                   // #150
3066 NULL,                                                   // #151
3067 NULL,                                                   // #152
3068 NULL,                                                   // #153
3069 NULL,                                                   // #154
3070 NULL,                                                   // #155
3071 NULL,                                                   // #156
3072 NULL,                                                   // #157
3073 NULL,                                                   // #158
3074 NULL,                                                   // #159
3075 NULL,                                                   // #160
3076 NULL,                                                   // #161
3077 NULL,                                                   // #162
3078 NULL,                                                   // #163
3079 NULL,                                                   // #164
3080 NULL,                                                   // #165
3081 NULL,                                                   // #166
3082 NULL,                                                   // #167
3083 NULL,                                                   // #168
3084 NULL,                                                   // #169
3085 NULL,                                                   // #170
3086 NULL,                                                   // #171
3087 NULL,                                                   // #172
3088 NULL,                                                   // #173
3089 NULL,                                                   // #174
3090 NULL,                                                   // #175
3091 NULL,                                                   // #176
3092 NULL,                                                   // #177
3093 NULL,                                                   // #178
3094 NULL,                                                   // #179
3095 NULL,                                                   // #180
3096 NULL,                                                   // #181
3097 NULL,                                                   // #182
3098 NULL,                                                   // #183
3099 NULL,                                                   // #184
3100 NULL,                                                   // #185
3101 NULL,                                                   // #186
3102 NULL,                                                   // #187
3103 NULL,                                                   // #188
3104 NULL,                                                   // #189
3105 NULL,                                                   // #190
3106 NULL,                                                   // #191
3107 NULL,                                                   // #192
3108 NULL,                                                   // #193
3109 NULL,                                                   // #194
3110 NULL,                                                   // #195
3111 NULL,                                                   // #196
3112 NULL,                                                   // #197
3113 NULL,                                                   // #198
3114 NULL,                                                   // #199
3115 // FTEQW range #200-#299
3116 NULL,                                                   // #200
3117 NULL,                                                   // #201
3118 NULL,                                                   // #202
3119 NULL,                                                   // #203
3120 NULL,                                                   // #204
3121 NULL,                                                   // #205
3122 NULL,                                                   // #206
3123 NULL,                                                   // #207
3124 NULL,                                                   // #208
3125 NULL,                                                   // #209
3126 NULL,                                                   // #210
3127 NULL,                                                   // #211
3128 NULL,                                                   // #212
3129 NULL,                                                   // #213
3130 NULL,                                                   // #214
3131 NULL,                                                   // #215
3132 NULL,                                                   // #216
3133 NULL,                                                   // #217
3134 VM_bitshift,                                    // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3135 NULL,                                                   // #219
3136 NULL,                                                   // #220
3137 VM_strstrofs,                                   // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3138 VM_str2chr,                                             // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3139 VM_chr2str,                                             // #223 string(float c, ...) chr2str (FTE_STRINGS)
3140 VM_strconv,                                             // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3141 VM_strpad,                                              // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3142 VM_infoadd,                                             // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3143 VM_infoget,                                             // #227 string(string info, string key) infoget (FTE_STRINGS)
3144 VM_strncmp,                                             // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3145 VM_strncasecmp,                                 // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3146 VM_strncasecmp,                                 // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3147 NULL,                                                   // #231
3148 NULL,                                                   // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3149 NULL,                                                   // #233
3150 NULL,                                                   // #234
3151 NULL,                                                   // #235
3152 NULL,                                                   // #236
3153 NULL,                                                   // #237
3154 NULL,                                                   // #238
3155 NULL,                                                   // #239
3156 NULL,                                                   // #240
3157 NULL,                                                   // #241
3158 NULL,                                                   // #242
3159 NULL,                                                   // #243
3160 NULL,                                                   // #244
3161 NULL,                                                   // #245
3162 NULL,                                                   // #246
3163 NULL,                                                   // #247
3164 NULL,                                                   // #248
3165 NULL,                                                   // #249
3166 NULL,                                                   // #250
3167 NULL,                                                   // #251
3168 NULL,                                                   // #252
3169 NULL,                                                   // #253
3170 NULL,                                                   // #254
3171 NULL,                                                   // #255
3172 NULL,                                                   // #256
3173 NULL,                                                   // #257
3174 NULL,                                                   // #258
3175 NULL,                                                   // #259
3176 NULL,                                                   // #260
3177 NULL,                                                   // #261
3178 NULL,                                                   // #262
3179 NULL,                                                   // #263
3180 NULL,                                                   // #264
3181 NULL,                                                   // #265
3182 NULL,                                                   // #266
3183 NULL,                                                   // #267
3184 NULL,                                                   // #268
3185 NULL,                                                   // #269
3186 NULL,                                                   // #270
3187 NULL,                                                   // #271
3188 NULL,                                                   // #272
3189 NULL,                                                   // #273
3190 NULL,                                                   // #274
3191 NULL,                                                   // #275
3192 NULL,                                                   // #276
3193 NULL,                                                   // #277
3194 NULL,                                                   // #278
3195 NULL,                                                   // #279
3196 NULL,                                                   // #280
3197 NULL,                                                   // #281
3198 NULL,                                                   // #282
3199 NULL,                                                   // #283
3200 NULL,                                                   // #284
3201 NULL,                                                   // #285
3202 NULL,                                                   // #286
3203 NULL,                                                   // #287
3204 NULL,                                                   // #288
3205 NULL,                                                   // #289
3206 NULL,                                                   // #290
3207 NULL,                                                   // #291
3208 NULL,                                                   // #292
3209 NULL,                                                   // #293
3210 NULL,                                                   // #294
3211 NULL,                                                   // #295
3212 NULL,                                                   // #296
3213 NULL,                                                   // #297
3214 NULL,                                                   // #298
3215 NULL,                                                   // #299
3216 // CSQC range #300-#399
3217 VM_CL_R_ClearScene,                             // #300 void() clearscene (EXT_CSQC)
3218 VM_CL_R_AddEntities,                    // #301 void(float mask) addentities (EXT_CSQC)
3219 VM_CL_R_AddEntity,                              // #302 void(entity ent) addentity (EXT_CSQC)
3220 VM_CL_R_SetView,                                // #303 float(float property, ...) setproperty (EXT_CSQC)
3221 VM_CL_R_RenderScene,                    // #304 void() renderscene (EXT_CSQC)
3222 VM_CL_R_AddDynamicLight,                // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3223 VM_CL_R_PolygonBegin,                   // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3224 VM_CL_R_PolygonVertex,                  // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3225 VM_CL_R_PolygonEnd,                             // #308 void() R_EndPolygon
3226 NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
3227 VM_CL_unproject,                                // #310 vector (vector v) cs_unproject (EXT_CSQC)
3228 VM_CL_project,                                  // #311 vector (vector v) cs_project (EXT_CSQC)
3229 NULL,                                                   // #312
3230 NULL,                                                   // #313
3231 NULL,                                                   // #314
3232 VM_drawline,                                    // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3233 VM_iscachedpic,                                 // #316 float(string name) iscachedpic (EXT_CSQC)
3234 VM_precache_pic,                                // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3235 VM_getimagesize,                                // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3236 VM_freepic,                                             // #319 void(string name) freepic (EXT_CSQC)
3237 VM_drawcharacter,                               // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3238 VM_drawstring,                                  // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3239 VM_drawpic,                                             // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3240 VM_drawfill,                                    // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3241 VM_drawsetcliparea,                             // #324 void(float x, float y, float width, float height) drawsetcliparea
3242 VM_drawresetcliparea,                   // #325 void(void) drawresetcliparea
3243 VM_drawcolorcodedstring,                // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3244 NULL,                                                   // #327 // FIXME add stringwidth() here?
3245 NULL,                                                   // #328 // FIXME add drawsubpic() here?
3246 NULL,                                                   // #329
3247 VM_CL_getstatf,                                 // #330 float(float stnum) getstatf (EXT_CSQC)
3248 VM_CL_getstati,                                 // #331 float(float stnum) getstati (EXT_CSQC)
3249 VM_CL_getstats,                                 // #332 string(float firststnum) getstats (EXT_CSQC)
3250 VM_CL_setmodelindex,                    // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3251 VM_CL_modelnameforindex,                // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3252 VM_CL_particleeffectnum,                // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3253 VM_CL_trailparticles,                   // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3254 VM_CL_pointparticles,                   // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3255 VM_centerprint,                                 // #338 void(string s, ...) centerprint (EXT_CSQC)
3256 VM_print,                                               // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3257 VM_keynumtostring,                              // #340 string(float keynum) keynumtostring (EXT_CSQC)
3258 VM_stringtokeynum,                              // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3259 VM_CL_getkeybind,                               // #342 string(float keynum) getkeybind (EXT_CSQC)
3260 VM_CL_setcursormode,                    // #343 void(float usecursor) setcursormode (EXT_CSQC)
3261 VM_CL_getmousepos,                              // #344 vector() getmousepos (EXT_CSQC)
3262 VM_CL_getinputstate,                    // #345 float(float framenum) getinputstate (EXT_CSQC)
3263 VM_CL_setsensitivityscale,              // #346 void(float sens) setsensitivityscale (EXT_CSQC)
3264 VM_CL_runplayerphysics,                 // #347 void() runstandardplayerphysics (EXT_CSQC)
3265 VM_CL_getplayerkey,                             // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3266 VM_CL_isdemo,                                   // #349 float() isdemo (EXT_CSQC)
3267 VM_isserver,                                    // #350 float() isserver (EXT_CSQC)
3268 VM_CL_setlistener,                              // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3269 VM_CL_registercmd,                              // #352 void(string cmdname) registercommand (EXT_CSQC)
3270 VM_wasfreed,                                    // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3271 VM_CL_serverkey,                                // #354 string(string key) serverkey (EXT_CSQC)
3272 NULL,                                                   // #355
3273 NULL,                                                   // #356
3274 NULL,                                                   // #357
3275 NULL,                                                   // #358
3276 NULL,                                                   // #359
3277 VM_CL_ReadByte,                                 // #360 float() readbyte (EXT_CSQC)
3278 VM_CL_ReadChar,                                 // #361 float() readchar (EXT_CSQC)
3279 VM_CL_ReadShort,                                // #362 float() readshort (EXT_CSQC)
3280 VM_CL_ReadLong,                                 // #363 float() readlong (EXT_CSQC)
3281 VM_CL_ReadCoord,                                // #364 float() readcoord (EXT_CSQC)
3282 VM_CL_ReadAngle,                                // #365 float() readangle (EXT_CSQC)
3283 VM_CL_ReadString,                               // #366 string() readstring (EXT_CSQC)
3284 VM_CL_ReadFloat,                                // #367 float() readfloat (EXT_CSQC)
3285 NULL,                                           // #368
3286 NULL,                                                   // #369
3287 NULL,                                                   // #370
3288 NULL,                                                   // #371
3289 NULL,                                                   // #372
3290 NULL,                                                   // #373
3291 NULL,                                                   // #374
3292 NULL,                                                   // #375
3293 NULL,                                                   // #376
3294 NULL,                                                   // #377
3295 NULL,                                                   // #378
3296 NULL,                                                   // #379
3297 NULL,                                                   // #380
3298 NULL,                                                   // #381
3299 NULL,                                                   // #382
3300 NULL,                                                   // #383
3301 NULL,                                                   // #384
3302 NULL,                                                   // #385
3303 NULL,                                                   // #386
3304 NULL,                                                   // #387
3305 NULL,                                                   // #388
3306 NULL,                                                   // #389
3307 NULL,                                                   // #390
3308 NULL,                                                   // #391
3309 NULL,                                                   // #392
3310 NULL,                                                   // #393
3311 NULL,                                                   // #394
3312 NULL,                                                   // #395
3313 NULL,                                                   // #396
3314 NULL,                                                   // #397
3315 NULL,                                                   // #398
3316 NULL,                                                   // #399
3317 // LordHavoc's range #400-#499
3318 VM_CL_copyentity,                               // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3319 NULL,                                                   // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3320 VM_findchain,                                   // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3321 VM_findchainfloat,                              // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3322 VM_CL_effect,                                   // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3323 VM_CL_te_blood,                                 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3324 VM_CL_te_bloodshower,                   // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3325 VM_CL_te_explosionrgb,                  // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3326 VM_CL_te_particlecube,                  // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3327 VM_CL_te_particlerain,                  // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3328 VM_CL_te_particlesnow,                  // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3329 VM_CL_te_spark,                                 // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3330 VM_CL_te_gunshotquad,                   // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3331 VM_CL_te_spikequad,                             // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3332 VM_CL_te_superspikequad,                // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3333 VM_CL_te_explosionquad,                 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3334 VM_CL_te_smallflash,                    // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3335 VM_CL_te_customflash,                   // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3336 VM_CL_te_gunshot,                               // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3337 VM_CL_te_spike,                                 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3338 VM_CL_te_superspike,                    // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3339 VM_CL_te_explosion,                             // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3340 VM_CL_te_tarexplosion,                  // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3341 VM_CL_te_wizspike,                              // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3342 VM_CL_te_knightspike,                   // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3343 VM_CL_te_lavasplash,                    // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3344 VM_CL_te_teleport,                              // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3345 VM_CL_te_explosion2,                    // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3346 VM_CL_te_lightning1,                    // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3347 VM_CL_te_lightning2,                    // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3348 VM_CL_te_lightning3,                    // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3349 VM_CL_te_beam,                                  // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3350 VM_vectorvectors,                               // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3351 VM_CL_te_plasmaburn,                    // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3352 VM_CL_getsurfacenumpoints,              // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3353 VM_CL_getsurfacepoint,                  // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3354 VM_CL_getsurfacenormal,                 // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3355 VM_CL_getsurfacetexture,                // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3356 VM_CL_getsurfacenearpoint,              // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3357 VM_CL_getsurfaceclippedpoint,   // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3358 NULL,                                                   // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3359 VM_tokenize,                                    // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3360 VM_argv,                                                // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3361 VM_CL_setattachment,                    // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3362 VM_search_begin,                                // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3363 VM_search_end,                                  // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3364 VM_search_getsize,                              // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3365 VM_search_getfilename,                  // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3366 VM_cvar_string,                                 // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3367 VM_findflags,                                   // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3368 VM_findchainflags,                              // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3369 VM_CL_gettagindex,                              // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3370 VM_CL_gettaginfo,                               // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3371 NULL,                                                   // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3372 NULL,                                                   // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3373 NULL,                                                   // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3374 NULL,                                                   // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3375 VM_CL_te_flamejet,                              // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
3376 NULL,                                                   // #458
3377 VM_ftoe,                                                // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3378 VM_buf_create,                                  // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3379 VM_buf_del,                                             // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3380 VM_buf_getsize,                                 // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3381 VM_buf_copy,                                    // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3382 VM_buf_sort,                                    // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3383 VM_buf_implode,                                 // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3384 VM_bufstr_get,                                  // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3385 VM_bufstr_set,                                  // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3386 VM_bufstr_add,                                  // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3387 VM_bufstr_free,                                 // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3388 NULL,                                                   // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3389 VM_asin,                                                // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3390 VM_acos,                                                // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3391 VM_atan,                                                // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3392 VM_atan2,                                               // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3393 VM_tan,                                                 // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3394 VM_strlennocol,                                 // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3395 VM_strdecolorize,                               // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3396 VM_strftime,                                    // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3397 VM_tokenizebyseparator,                 // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3398 VM_strtolower,                                  // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3399 VM_strtoupper,                                  // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3400 VM_cvar_defstring,                              // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3401 VM_CL_pointsound,                               // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
3402 VM_strreplace,                                  // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3403 VM_strireplace,                                 // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3404 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
3405 VM_gecko_create,                                        // #487 float gecko_create( string name )
3406 VM_gecko_destroy,                                       // #488 void gecko_destroy( string name )
3407 VM_gecko_navigate,                              // #489 void gecko_navigate( string name, string URI )
3408 VM_gecko_keyevent,                              // #490 float gecko_keyevent( string name, float key, float eventtype )
3409 VM_gecko_movemouse,                             // #491 void gecko_mousemove( string name, float x, float y )
3410 VM_gecko_resize,                                        // #492 void gecko_resize( string name, float w, float h )
3411 VM_gecko_get_texture_extent,    // #493 vector gecko_get_texture_extent( string name )
3412 VM_crc16,                                               // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3413 VM_cvar_type,                                   // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3414 NULL,                                                   // #496
3415 NULL,                                                   // #497
3416 NULL,                                                   // #498
3417 NULL,                                                   // #499
3418 NULL,                                                   // #500
3419 NULL,                                                   // #501
3420 NULL,                                                   // #502
3421 NULL,                                                   // #503
3422 NULL,                                                   // #504
3423 NULL,                                                   // #505
3424 NULL,                                                   // #506
3425 NULL,                                                   // #507
3426 NULL,                                                   // #508
3427 NULL,                                                   // #509
3428 VM_uri_escape,                                  // #510 string(string in) uri_escape = #510;
3429 VM_uri_unescape,                                // #511 string(string in) uri_unescape = #511;
3430 VM_etof,                                        // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3431 NULL,                                                   // #513
3432 NULL,                                                   // #514
3433 NULL,                                                   // #515
3434 NULL,                                                   // #516
3435 NULL,                                                   // #517
3436 NULL,                                                   // #518
3437 NULL,                                                   // #519
3438 };
3439
3440 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3441
3442 void VM_Polygons_Reset(void)
3443 {
3444         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
3445
3446         // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3447         if(polys->initialized)
3448         {
3449                 Mem_FreePool(&polys->pool);
3450                 polys->initialized = false;
3451         }
3452 }
3453
3454 void VM_CL_Cmd_Init(void)
3455 {
3456         VM_Cmd_Init();
3457         VM_Polygons_Reset();
3458 }
3459
3460 void VM_CL_Cmd_Reset(void)
3461 {
3462         VM_Cmd_Reset();
3463         VM_Polygons_Reset();
3464 }
3465
3466