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