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