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