]> git.xonotic.org Git - xonotic/darkplaces.git/blob - clvm_cmds.c
Fixed crash in CL_GetTagMatrix when no 'scale' entity field is present.
[xonotic/darkplaces.git] / clvm_cmds.c
1 #include "quakedef.h"
2
3 #include "prvm_cmds.h"
4 #include "csprogs.h"
5 #include "cl_collision.h"
6 #include "r_shadow.h"
7
8 //============================================================================
9 // Client
10 //[515]: unsolved PROBLEMS
11 //- finish player physics code (cs_runplayerphysics)
12 //- EntWasFreed ?
13 //- RF_DEPTHHACK is not like it should be
14 //- add builtin that sets cl.viewangles instead of reading "input_angles" global
15 //- finish lines support for R_Polygon***
16 //- insert selecttraceline into traceline somehow
17
18 //4 feature darkplaces csqc: add builtin to clientside qc for reading triangles of model meshes (useful to orient a ui along a triangle of a model mesh)
19 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
20
21 sfx_t *S_FindName(const char *name);
22 int Sbar_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         if(modelindex < 0)
2183                 modelindex = -(modelindex+1);
2184         tag_index = 0;
2185         if (modelindex <= 0 || modelindex >= MAX_MODELS)
2186                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2187         else
2188         {
2189                 tag_index = CL_GetTagIndex(ent, tag_name);
2190                 if (tag_index == 0)
2191                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2192         }
2193         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2194 }
2195
2196 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2197 static void VM_CL_gettaginfo (void)
2198 {
2199         prvm_edict_t *e;
2200         int tagindex;
2201         matrix4x4_t tag_matrix;
2202         int returncode;
2203
2204         VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2205
2206         e = PRVM_G_EDICT(OFS_PARM0);
2207         tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2208         returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2209         Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2210
2211         switch(returncode)
2212         {
2213                 case 1:
2214                         VM_Warning("gettagindex: can't affect world entity\n");
2215                         break;
2216                 case 2:
2217                         VM_Warning("gettagindex: can't affect free entity\n");
2218                         break;
2219                 case 3:
2220                         Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2221                         break;
2222                 case 4:
2223                         Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2224                         break;
2225                 case 5:
2226                         Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2227                         break;
2228         }
2229 }
2230
2231 //============================================================================
2232
2233 //====================
2234 //QC POLYGON functions
2235 //====================
2236
2237 typedef struct
2238 {
2239         rtexture_t              *tex;
2240         float                   data[36];       //[515]: enough for polygons
2241         unsigned char                   flags;  //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2242 }vm_polygon_t;
2243
2244 //static float                  vm_polygon_linewidth = 1;
2245 static mempool_t                *vm_polygons_pool = NULL;
2246 static unsigned char                    vm_current_vertices = 0;
2247 static qboolean                 vm_polygons_initialized = false;
2248 static vm_polygon_t             *vm_polygons = NULL;
2249 static unsigned long    vm_polygons_num = 0, vm_drawpolygons_num = 0;   //[515]: ok long on 64bit ?
2250 static qboolean                 vm_polygonbegin = false;        //[515]: for "no-crap-on-the-screen" check
2251 #define VM_DEFPOLYNUM 64        //[515]: enough for default ?
2252
2253 #define VM_POLYGON_FL3V         16      //more than 2 vertices (used only for lines)
2254 #define VM_POLYGON_FLLINES      32
2255 #define VM_POLYGON_FL2D         64
2256 #define VM_POLYGON_FL4V         128     //4 vertices
2257
2258 static void VM_InitPolygons (void)
2259 {
2260         vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2261         vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2262         memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2263         vm_polygons_num = VM_DEFPOLYNUM;
2264         vm_drawpolygons_num = 0;
2265         vm_polygonbegin = false;
2266         vm_polygons_initialized = true;
2267 }
2268
2269 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2270 {
2271         int surfacelistindex;
2272         // LordHavoc: FIXME: this is stupid code
2273         for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2274         {
2275                 const vm_polygon_t      *p = &vm_polygons[surfacelist[surfacelistindex]];
2276                 int                                     flags = p->flags & 0x0f;
2277
2278                 if(flags == DRAWFLAG_ADDITIVE)
2279                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2280                 else if(flags == DRAWFLAG_MODULATE)
2281                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2282                 else if(flags == DRAWFLAG_2XMODULATE)
2283                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2284                 else
2285                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2286
2287                 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2288
2289                 CHECKGLERROR
2290                 //[515]: is speed is max ?
2291                 if(p->flags & VM_POLYGON_FLLINES)       //[515]: lines
2292                 {
2293                         qglLineWidth(p->data[13]);CHECKGLERROR
2294                         qglBegin(GL_LINE_LOOP);
2295                                 qglTexCoord1f   (p->data[12]);
2296                                 qglColor4f              (p->data[20], p->data[21], p->data[22], p->data[23]);
2297                                 qglVertex3f             (p->data[0] , p->data[1],  p->data[2]);
2298
2299                                 qglTexCoord1f   (p->data[14]);
2300                                 qglColor4f              (p->data[24], p->data[25], p->data[26], p->data[27]);
2301                                 qglVertex3f             (p->data[3] , p->data[4],  p->data[5]);
2302
2303                                 if(p->flags & VM_POLYGON_FL3V)
2304                                 {
2305                                         qglTexCoord1f   (p->data[16]);
2306                                         qglColor4f              (p->data[28], p->data[29], p->data[30], p->data[31]);
2307                                         qglVertex3f             (p->data[6] , p->data[7],  p->data[8]);
2308
2309                                         if(p->flags & VM_POLYGON_FL4V)
2310                                         {
2311                                                 qglTexCoord1f   (p->data[18]);
2312                                                 qglColor4f              (p->data[32], p->data[33], p->data[34], p->data[35]);
2313                                                 qglVertex3f             (p->data[9] , p->data[10],  p->data[11]);
2314                                         }
2315                                 }
2316                         qglEnd();
2317                         CHECKGLERROR
2318                 }
2319                 else
2320                 {
2321                         qglBegin(GL_POLYGON);
2322                                 qglTexCoord2f   (p->data[12], p->data[13]);
2323                                 qglColor4f              (p->data[20], p->data[21], p->data[22], p->data[23]);
2324                                 qglVertex3f             (p->data[0] , p->data[1],  p->data[2]);
2325
2326                                 qglTexCoord2f   (p->data[14], p->data[15]);
2327                                 qglColor4f              (p->data[24], p->data[25], p->data[26], p->data[27]);
2328                                 qglVertex3f             (p->data[3] , p->data[4],  p->data[5]);
2329
2330                                 qglTexCoord2f   (p->data[16], p->data[17]);
2331                                 qglColor4f              (p->data[28], p->data[29], p->data[30], p->data[31]);
2332                                 qglVertex3f             (p->data[6] , p->data[7],  p->data[8]);
2333
2334                                 if(p->flags & VM_POLYGON_FL4V)
2335                                 {
2336                                         qglTexCoord2f   (p->data[18], p->data[19]);
2337                                         qglColor4f              (p->data[32], p->data[33], p->data[34], p->data[35]);
2338                                         qglVertex3f             (p->data[9] , p->data[10],  p->data[11]);
2339                                 }
2340                         qglEnd();
2341                         CHECKGLERROR
2342                 }
2343         }
2344 }
2345
2346 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2347 {
2348         drawqueuemesh_t mesh;
2349         static int              picelements[6] = {0, 1, 2, 0, 2, 3};
2350
2351         mesh.texture = p->tex;
2352         mesh.data_element3i = picelements;
2353         mesh.data_vertex3f = p->data;
2354         mesh.data_texcoord2f = p->data + 12;
2355         mesh.data_color4f = p->data + 20;
2356         if(p->flags & VM_POLYGON_FL4V)
2357         {
2358                 mesh.num_vertices = 4;
2359                 mesh.num_triangles = 2;
2360         }
2361         else
2362         {
2363                 mesh.num_vertices = 3;
2364                 mesh.num_triangles = 1;
2365         }
2366         if(p->flags & VM_POLYGON_FLLINES)       //[515]: lines
2367                 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2368         else
2369                 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2370 }
2371
2372 void VM_CL_AddPolygonsToMeshQueue (void)
2373 {
2374         int i;
2375         if(!vm_drawpolygons_num)
2376                 return;
2377         R_Mesh_Matrix(&identitymatrix);
2378         GL_CullFace(GL_NONE);
2379         for(i = 0;i < (int)vm_drawpolygons_num;i++)
2380                 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2381         vm_drawpolygons_num = 0;
2382 }
2383
2384 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2385 static void VM_CL_R_PolygonBegin (void)
2386 {
2387         vm_polygon_t    *p;
2388         const char              *picname;
2389         VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2390
2391         if(!vm_polygons_initialized)
2392                 VM_InitPolygons();
2393         if(vm_polygonbegin)
2394         {
2395                 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2396                 return;
2397         }
2398         if(vm_drawpolygons_num >= vm_polygons_num)
2399         {
2400                 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2401                 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2402                 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2403                 Mem_Free(vm_polygons);
2404                 vm_polygons = p;
2405                 vm_polygons_num *= 2;
2406         }
2407         p = &vm_polygons[vm_drawpolygons_num];
2408         picname = PRVM_G_STRING(OFS_PARM0);
2409         if(picname[0])
2410                 p->tex = Draw_CachePic(picname, true)->tex;
2411         else
2412                 p->tex = r_texture_white;
2413         p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2414         vm_current_vertices = 0;
2415         vm_polygonbegin = true;
2416         if(prog->argc >= 3)
2417         {
2418                 if(PRVM_G_FLOAT(OFS_PARM2))
2419                         p->flags |= VM_POLYGON_FL2D;
2420                 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2421                 {
2422                         p->data[13] = PRVM_G_FLOAT(OFS_PARM3);  //[515]: linewidth
2423                         p->flags |= VM_POLYGON_FLLINES;
2424                 }
2425         }
2426 }
2427
2428 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2429 static void VM_CL_R_PolygonVertex (void)
2430 {
2431         float                   *coords, *tx, *rgb, alpha;
2432         vm_polygon_t    *p;
2433         VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2434
2435         if(!vm_polygonbegin)
2436         {
2437                 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2438                 return;
2439         }
2440         coords  = PRVM_G_VECTOR(OFS_PARM0);
2441         tx              = PRVM_G_VECTOR(OFS_PARM1);
2442         rgb             = PRVM_G_VECTOR(OFS_PARM2);
2443         alpha = PRVM_G_FLOAT(OFS_PARM3);
2444
2445         p = &vm_polygons[vm_drawpolygons_num];
2446         if(vm_current_vertices > 4)
2447         {
2448                 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2449                 return;
2450         }
2451
2452         p->data[vm_current_vertices*3]          = coords[0];
2453         p->data[1+vm_current_vertices*3]        = coords[1];
2454         p->data[2+vm_current_vertices*3]        = coords[2];
2455
2456         p->data[12+vm_current_vertices*2]       = tx[0];
2457         if(!(p->flags & VM_POLYGON_FLLINES))
2458                 p->data[13+vm_current_vertices*2]       = tx[1];
2459
2460         p->data[20+vm_current_vertices*4]       = rgb[0];
2461         p->data[21+vm_current_vertices*4]       = rgb[1];
2462         p->data[22+vm_current_vertices*4]       = rgb[2];
2463         p->data[23+vm_current_vertices*4]       = alpha;
2464
2465         vm_current_vertices++;
2466         if(vm_current_vertices == 4)
2467                 p->flags |= VM_POLYGON_FL4V;
2468         else
2469                 if(vm_current_vertices == 3)
2470                         p->flags |= VM_POLYGON_FL3V;
2471 }
2472
2473 //void() R_EndPolygon
2474 static void VM_CL_R_PolygonEnd (void)
2475 {
2476         VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2477         if(!vm_polygonbegin)
2478         {
2479                 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2480                 return;
2481         }
2482         vm_polygonbegin = false;
2483         if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2484         {
2485                 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D)    //[515]: don't use qcpolygons memory if 2D
2486                         VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2487                 else
2488                         vm_drawpolygons_num++;
2489         }
2490         else
2491                 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2492 }
2493
2494 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2495 {
2496         vm_polygon_t    *p;
2497
2498         if(!vm_polygons_initialized)
2499                 VM_InitPolygons();
2500         if(vm_polygonbegin)
2501         {
2502                 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2503                 return;
2504         }
2505         // limit polygons to a vaguely sane amount, beyond this each one just
2506         // replaces the last one
2507         vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2508         if(vm_drawpolygons_num >= vm_polygons_num)
2509         {
2510                 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2511                 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2512                 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2513                 Mem_Free(vm_polygons);
2514                 vm_polygons = p;
2515                 vm_polygons_num *= 2;
2516         }
2517         p = &vm_polygons[vm_drawpolygons_num];
2518         if(picname && picname[0])
2519                 p->tex = Draw_CachePic(picname, true)->tex;
2520         else
2521                 p->tex = r_texture_white;
2522         p->flags = flags;
2523         vm_current_vertices = 0;
2524         vm_polygonbegin = true;
2525         if(draw2d)
2526                 p->flags |= VM_POLYGON_FL2D;
2527         if(linewidth)
2528         {
2529                 p->data[13] = linewidth;        //[515]: linewidth
2530                 p->flags |= VM_POLYGON_FLLINES;
2531         }
2532 }
2533
2534 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2535 {
2536         vm_polygon_t    *p;
2537
2538         if(!vm_polygonbegin)
2539         {
2540                 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2541                 return;
2542         }
2543
2544         p = &vm_polygons[vm_drawpolygons_num];
2545         if(vm_current_vertices > 4)
2546         {
2547                 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2548                 return;
2549         }
2550
2551         p->data[vm_current_vertices*3]          = x;
2552         p->data[1+vm_current_vertices*3]        = y;
2553         p->data[2+vm_current_vertices*3]        = z;
2554
2555         p->data[12+vm_current_vertices*2]       = s;
2556         if(!(p->flags & VM_POLYGON_FLLINES))
2557                 p->data[13+vm_current_vertices*2]       = t;
2558
2559         p->data[20+vm_current_vertices*4]       = r;
2560         p->data[21+vm_current_vertices*4]       = g;
2561         p->data[22+vm_current_vertices*4]       = b;
2562         p->data[23+vm_current_vertices*4]       = a;
2563
2564         vm_current_vertices++;
2565         if(vm_current_vertices == 4)
2566                 p->flags |= VM_POLYGON_FL4V;
2567         else
2568                 if(vm_current_vertices == 3)
2569                         p->flags |= VM_POLYGON_FL3V;
2570 }
2571
2572 void Debug_PolygonEnd(void)
2573 {
2574         if(!vm_polygonbegin)
2575         {
2576                 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2577                 return;
2578         }
2579         vm_polygonbegin = false;
2580         if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2581         {
2582                 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D)    //[515]: don't use qcpolygons memory if 2D
2583                         VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2584                 else
2585                         vm_drawpolygons_num++;
2586         }
2587         else
2588                 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2589 }
2590
2591 /*
2592 =============
2593 CL_CheckBottom
2594
2595 Returns false if any part of the bottom of the entity is off an edge that
2596 is not a staircase.
2597
2598 =============
2599 */
2600 qboolean CL_CheckBottom (prvm_edict_t *ent)
2601 {
2602         vec3_t  mins, maxs, start, stop;
2603         trace_t trace;
2604         int             x, y;
2605         float   mid, bottom;
2606
2607         VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2608         VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2609
2610 // if all of the points under the corners are solid world, don't bother
2611 // with the tougher checks
2612 // the corners must be within 16 of the midpoint
2613         start[2] = mins[2] - 1;
2614         for     (x=0 ; x<=1 ; x++)
2615                 for     (y=0 ; y<=1 ; y++)
2616                 {
2617                         start[0] = x ? maxs[0] : mins[0];
2618                         start[1] = y ? maxs[1] : mins[1];
2619                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2620                                 goto realcheck;
2621                 }
2622
2623         return true;            // we got out easy
2624
2625 realcheck:
2626 //
2627 // check it for real...
2628 //
2629         start[2] = mins[2];
2630
2631 // the midpoint must be within 16 of the bottom
2632         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2633         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2634         stop[2] = start[2] - 2*sv_stepheight.value;
2635         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2636
2637         if (trace.fraction == 1.0)
2638                 return false;
2639         mid = bottom = trace.endpos[2];
2640
2641 // the corners must be within 16 of the midpoint
2642         for     (x=0 ; x<=1 ; x++)
2643                 for     (y=0 ; y<=1 ; y++)
2644                 {
2645                         start[0] = stop[0] = x ? maxs[0] : mins[0];
2646                         start[1] = stop[1] = y ? maxs[1] : mins[1];
2647
2648                         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2649
2650                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2651                                 bottom = trace.endpos[2];
2652                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2653                                 return false;
2654                 }
2655
2656         return true;
2657 }
2658
2659 /*
2660 =============
2661 CL_movestep
2662
2663 Called by monster program code.
2664 The move will be adjusted for slopes and stairs, but if the move isn't
2665 possible, no move is done and false is returned
2666 =============
2667 */
2668 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2669 {
2670         float           dz;
2671         vec3_t          oldorg, neworg, end, traceendpos;
2672         trace_t         trace;
2673         int                     i;
2674         prvm_edict_t            *enemy;
2675         prvm_eval_t     *val;
2676
2677 // try the move
2678         VectorCopy (ent->fields.client->origin, oldorg);
2679         VectorAdd (ent->fields.client->origin, move, neworg);
2680
2681 // flying monsters don't step up
2682         if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2683         {
2684         // try one move with vertical motion, then one without
2685                 for (i=0 ; i<2 ; i++)
2686                 {
2687                         VectorAdd (ent->fields.client->origin, move, neworg);
2688                         enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2689                         if (i == 0 && enemy != prog->edicts)
2690                         {
2691                                 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2692                                 if (dz > 40)
2693                                         neworg[2] -= 8;
2694                                 if (dz < 30)
2695                                         neworg[2] += 8;
2696                         }
2697                         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);
2698                         if (settrace)
2699                                 VM_SetTraceGlobals(&trace);
2700
2701                         if (trace.fraction == 1)
2702                         {
2703                                 VectorCopy(trace.endpos, traceendpos);
2704                                 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2705                                         return false;   // swim monster left water
2706
2707                                 VectorCopy (traceendpos, ent->fields.client->origin);
2708                                 if (relink)
2709                                         CL_LinkEdict(ent);
2710                                 return true;
2711                         }
2712
2713                         if (enemy == prog->edicts)
2714                                 break;
2715                 }
2716
2717                 return false;
2718         }
2719
2720 // push down from a step height above the wished position
2721         neworg[2] += sv_stepheight.value;
2722         VectorCopy (neworg, end);
2723         end[2] -= sv_stepheight.value*2;
2724
2725         trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2726         if (settrace)
2727                 VM_SetTraceGlobals(&trace);
2728
2729         if (trace.startsolid)
2730         {
2731                 neworg[2] -= sv_stepheight.value;
2732                 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2733                 if (settrace)
2734                         VM_SetTraceGlobals(&trace);
2735                 if (trace.startsolid)
2736                         return false;
2737         }
2738         if (trace.fraction == 1)
2739         {
2740         // if monster had the ground pulled out, go ahead and fall
2741                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2742                 {
2743                         VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2744                         if (relink)
2745                                 CL_LinkEdict(ent);
2746                         ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2747                         return true;
2748                 }
2749
2750                 return false;           // walked off an edge
2751         }
2752
2753 // check point traces down for dangling corners
2754         VectorCopy (trace.endpos, ent->fields.client->origin);
2755
2756         if (!CL_CheckBottom (ent))
2757         {
2758                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2759                 {       // entity had floor mostly pulled out from underneath it
2760                         // and is trying to correct
2761                         if (relink)
2762                                 CL_LinkEdict(ent);
2763                         return true;
2764                 }
2765                 VectorCopy (oldorg, ent->fields.client->origin);
2766                 return false;
2767         }
2768
2769         if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2770                 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2771
2772         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2773                 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2774
2775 // the move is ok
2776         if (relink)
2777                 CL_LinkEdict(ent);
2778         return true;
2779 }
2780
2781 /*
2782 ===============
2783 VM_CL_walkmove
2784
2785 float(float yaw, float dist[, settrace]) walkmove
2786 ===============
2787 */
2788 static void VM_CL_walkmove (void)
2789 {
2790         prvm_edict_t    *ent;
2791         float   yaw, dist;
2792         vec3_t  move;
2793         mfunction_t     *oldf;
2794         int     oldself;
2795         qboolean        settrace;
2796
2797         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2798
2799         // assume failure if it returns early
2800         PRVM_G_FLOAT(OFS_RETURN) = 0;
2801
2802         ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2803         if (ent == prog->edicts)
2804         {
2805                 VM_Warning("walkmove: can not modify world entity\n");
2806                 return;
2807         }
2808         if (ent->priv.server->free)
2809         {
2810                 VM_Warning("walkmove: can not modify free entity\n");
2811                 return;
2812         }
2813         yaw = PRVM_G_FLOAT(OFS_PARM0);
2814         dist = PRVM_G_FLOAT(OFS_PARM1);
2815         settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2816
2817         if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2818                 return;
2819
2820         yaw = yaw*M_PI*2 / 360;
2821
2822         move[0] = cos(yaw)*dist;
2823         move[1] = sin(yaw)*dist;
2824         move[2] = 0;
2825
2826 // save program state, because CL_movestep may call other progs
2827         oldf = prog->xfunction;
2828         oldself = prog->globals.client->self;
2829
2830         PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2831
2832
2833 // restore program state
2834         prog->xfunction = oldf;
2835         prog->globals.client->self = oldself;
2836 }
2837
2838 /*
2839 ===============
2840 VM_CL_serverkey
2841
2842 string(string key) serverkey
2843 ===============
2844 */
2845 void VM_CL_serverkey(void)
2846 {
2847         char string[VM_STRINGTEMP_LENGTH];
2848         VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2849         InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2850         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2851 }
2852
2853 //============================================================================
2854
2855 prvm_builtin_t vm_cl_builtins[] = {
2856 NULL,                                                   // #0 NULL function (not callable) (QUAKE)
2857 VM_CL_makevectors,                              // #1 void(vector ang) makevectors (QUAKE)
2858 VM_CL_setorigin,                                // #2 void(entity e, vector o) setorigin (QUAKE)
2859 VM_CL_setmodel,                                 // #3 void(entity e, string m) setmodel (QUAKE)
2860 VM_CL_setsize,                                  // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2861 NULL,                                                   // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2862 VM_break,                                               // #6 void() break (QUAKE)
2863 VM_random,                                              // #7 float() random (QUAKE)
2864 VM_CL_sound,                                    // #8 void(entity e, float chan, string samp) sound (QUAKE)
2865 VM_normalize,                                   // #9 vector(vector v) normalize (QUAKE)
2866 VM_error,                                               // #10 void(string e) error (QUAKE)
2867 VM_objerror,                                    // #11 void(string e) objerror (QUAKE)
2868 VM_vlen,                                                // #12 float(vector v) vlen (QUAKE)
2869 VM_vectoyaw,                                    // #13 float(vector v) vectoyaw (QUAKE)
2870 VM_CL_spawn,                                    // #14 entity() spawn (QUAKE)
2871 VM_remove,                                              // #15 void(entity e) remove (QUAKE)
2872 VM_CL_traceline,                                // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2873 NULL,                                                   // #17 entity() checkclient (QUAKE)
2874 VM_find,                                                // #18 entity(entity start, .string fld, string match) find (QUAKE)
2875 VM_precache_sound,                              // #19 void(string s) precache_sound (QUAKE)
2876 VM_CL_precache_model,                   // #20 void(string s) precache_model (QUAKE)
2877 NULL,                                                   // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2878 VM_CL_findradius,                               // #22 entity(vector org, float rad) findradius (QUAKE)
2879 NULL,                                                   // #23 void(string s, ...) bprint (QUAKE)
2880 NULL,                                                   // #24 void(entity client, string s, ...) sprint (QUAKE)
2881 VM_dprint,                                              // #25 void(string s, ...) dprint (QUAKE)
2882 VM_ftos,                                                // #26 string(float f) ftos (QUAKE)
2883 VM_vtos,                                                // #27 string(vector v) vtos (QUAKE)
2884 VM_coredump,                                    // #28 void() coredump (QUAKE)
2885 VM_traceon,                                             // #29 void() traceon (QUAKE)
2886 VM_traceoff,                                    // #30 void() traceoff (QUAKE)
2887 VM_eprint,                                              // #31 void(entity e) eprint (QUAKE)
2888 VM_CL_walkmove,                                 // #32 float(float yaw, float dist) walkmove (QUAKE)
2889 NULL,                                                   // #33 (QUAKE)
2890 VM_CL_droptofloor,                              // #34 float() droptofloor (QUAKE)
2891 VM_CL_lightstyle,                               // #35 void(float style, string value) lightstyle (QUAKE)
2892 VM_rint,                                                // #36 float(float v) rint (QUAKE)
2893 VM_floor,                                               // #37 float(float v) floor (QUAKE)
2894 VM_ceil,                                                // #38 float(float v) ceil (QUAKE)
2895 NULL,                                                   // #39 (QUAKE)
2896 VM_CL_checkbottom,                              // #40 float(entity e) checkbottom (QUAKE)
2897 VM_CL_pointcontents,                    // #41 float(vector v) pointcontents (QUAKE)
2898 NULL,                                                   // #42 (QUAKE)
2899 VM_fabs,                                                // #43 float(float f) fabs (QUAKE)
2900 NULL,                                                   // #44 vector(entity e, float speed) aim (QUAKE)
2901 VM_cvar,                                                // #45 float(string s) cvar (QUAKE)
2902 VM_localcmd,                                    // #46 void(string s) localcmd (QUAKE)
2903 VM_nextent,                                             // #47 entity(entity e) nextent (QUAKE)
2904 VM_CL_particle,                                 // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2905 VM_changeyaw,                                   // #49 void() ChangeYaw (QUAKE)
2906 NULL,                                                   // #50 (QUAKE)
2907 VM_vectoangles,                                 // #51 vector(vector v) vectoangles (QUAKE)
2908 NULL,                                                   // #52 void(float to, float f) WriteByte (QUAKE)
2909 NULL,                                                   // #53 void(float to, float f) WriteChar (QUAKE)
2910 NULL,                                                   // #54 void(float to, float f) WriteShort (QUAKE)
2911 NULL,                                                   // #55 void(float to, float f) WriteLong (QUAKE)
2912 NULL,                                                   // #56 void(float to, float f) WriteCoord (QUAKE)
2913 NULL,                                                   // #57 void(float to, float f) WriteAngle (QUAKE)
2914 NULL,                                                   // #58 void(float to, string s) WriteString (QUAKE)
2915 NULL,                                                   // #59 (QUAKE)
2916 VM_sin,                                                 // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2917 VM_cos,                                                 // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2918 VM_sqrt,                                                // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2919 VM_changepitch,                                 // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2920 VM_CL_tracetoss,                                // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2921 VM_etos,                                                // #65 string(entity ent) etos (DP_QC_ETOS)
2922 NULL,                                                   // #66 (QUAKE)
2923 NULL,                                                   // #67 void(float step) movetogoal (QUAKE)
2924 VM_precache_file,                               // #68 string(string s) precache_file (QUAKE)
2925 VM_CL_makestatic,                               // #69 void(entity e) makestatic (QUAKE)
2926 NULL,                                                   // #70 void(string s) changelevel (QUAKE)
2927 NULL,                                                   // #71 (QUAKE)
2928 VM_cvar_set,                                    // #72 void(string var, string val) cvar_set (QUAKE)
2929 NULL,                                                   // #73 void(entity client, strings) centerprint (QUAKE)
2930 VM_CL_ambientsound,                             // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2931 VM_CL_precache_model,                   // #75 string(string s) precache_model2 (QUAKE)
2932 VM_precache_sound,                              // #76 string(string s) precache_sound2 (QUAKE)
2933 VM_precache_file,                               // #77 string(string s) precache_file2 (QUAKE)
2934 NULL,                                                   // #78 void(entity e) setspawnparms (QUAKE)
2935 NULL,                                                   // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2936 NULL,                                                   // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2937 VM_stof,                                                // #81 float(string s) stof (FRIK_FILE)
2938 NULL,                                                   // #82 void(vector where, float set) multicast (QUAKEWORLD)
2939 NULL,                                                   // #83 (QUAKE)
2940 NULL,                                                   // #84 (QUAKE)
2941 NULL,                                                   // #85 (QUAKE)
2942 NULL,                                                   // #86 (QUAKE)
2943 NULL,                                                   // #87 (QUAKE)
2944 NULL,                                                   // #88 (QUAKE)
2945 NULL,                                                   // #89 (QUAKE)
2946 VM_CL_tracebox,                                 // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2947 VM_randomvec,                                   // #91 vector() randomvec (DP_QC_RANDOMVEC)
2948 VM_CL_getlight,                                 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2949 VM_registercvar,                                // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2950 VM_min,                                                 // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2951 VM_max,                                                 // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2952 VM_bound,                                               // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2953 VM_pow,                                                 // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2954 VM_findfloat,                                   // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2955 VM_checkextension,                              // #99 float(string s) checkextension (the basis of the extension system)
2956 // FrikaC and Telejano range #100-#199
2957 NULL,                                                   // #100
2958 NULL,                                                   // #101
2959 NULL,                                                   // #102
2960 NULL,                                                   // #103
2961 NULL,                                                   // #104
2962 NULL,                                                   // #105
2963 NULL,                                                   // #106
2964 NULL,                                                   // #107
2965 NULL,                                                   // #108
2966 NULL,                                                   // #109
2967 VM_fopen,                                               // #110 float(string filename, float mode) fopen (FRIK_FILE)
2968 VM_fclose,                                              // #111 void(float fhandle) fclose (FRIK_FILE)
2969 VM_fgets,                                               // #112 string(float fhandle) fgets (FRIK_FILE)
2970 VM_fputs,                                               // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2971 VM_strlen,                                              // #114 float(string s) strlen (FRIK_FILE)
2972 VM_strcat,                                              // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2973 VM_substring,                                   // #116 string(string s, float start, float length) substring (FRIK_FILE)
2974 VM_stov,                                                // #117 vector(string) stov (FRIK_FILE)
2975 VM_strzone,                                             // #118 string(string s) strzone (FRIK_FILE)
2976 VM_strunzone,                                   // #119 void(string s) strunzone (FRIK_FILE)
2977 NULL,                                                   // #120
2978 NULL,                                                   // #121
2979 NULL,                                                   // #122
2980 NULL,                                                   // #123
2981 NULL,                                                   // #124
2982 NULL,                                                   // #125
2983 NULL,                                                   // #126
2984 NULL,                                                   // #127
2985 NULL,                                                   // #128
2986 NULL,                                                   // #129
2987 NULL,                                                   // #130
2988 NULL,                                                   // #131
2989 NULL,                                                   // #132
2990 NULL,                                                   // #133
2991 NULL,                                                   // #134
2992 NULL,                                                   // #135
2993 NULL,                                                   // #136
2994 NULL,                                                   // #137
2995 NULL,                                                   // #138
2996 NULL,                                                   // #139
2997 NULL,                                                   // #140
2998 NULL,                                                   // #141
2999 NULL,                                                   // #142
3000 NULL,                                                   // #143
3001 NULL,                                                   // #144
3002 NULL,                                                   // #145
3003 NULL,                                                   // #146
3004 NULL,                                                   // #147
3005 NULL,                                                   // #148
3006 NULL,                                                   // #149
3007 NULL,                                                   // #150
3008 NULL,                                                   // #151
3009 NULL,                                                   // #152
3010 NULL,                                                   // #153
3011 NULL,                                                   // #154
3012 NULL,                                                   // #155
3013 NULL,                                                   // #156
3014 NULL,                                                   // #157
3015 NULL,                                                   // #158
3016 NULL,                                                   // #159
3017 NULL,                                                   // #160
3018 NULL,                                                   // #161
3019 NULL,                                                   // #162
3020 NULL,                                                   // #163
3021 NULL,                                                   // #164
3022 NULL,                                                   // #165
3023 NULL,                                                   // #166
3024 NULL,                                                   // #167
3025 NULL,                                                   // #168
3026 NULL,                                                   // #169
3027 NULL,                                                   // #170
3028 NULL,                                                   // #171
3029 NULL,                                                   // #172
3030 NULL,                                                   // #173
3031 NULL,                                                   // #174
3032 NULL,                                                   // #175
3033 NULL,                                                   // #176
3034 NULL,                                                   // #177
3035 NULL,                                                   // #178
3036 NULL,                                                   // #179
3037 NULL,                                                   // #180
3038 NULL,                                                   // #181
3039 NULL,                                                   // #182
3040 NULL,                                                   // #183
3041 NULL,                                                   // #184
3042 NULL,                                                   // #185
3043 NULL,                                                   // #186
3044 NULL,                                                   // #187
3045 NULL,                                                   // #188
3046 NULL,                                                   // #189
3047 NULL,                                                   // #190
3048 NULL,                                                   // #191
3049 NULL,                                                   // #192
3050 NULL,                                                   // #193
3051 NULL,                                                   // #194
3052 NULL,                                                   // #195
3053 NULL,                                                   // #196
3054 NULL,                                                   // #197
3055 NULL,                                                   // #198
3056 NULL,                                                   // #199
3057 // FTEQW range #200-#299
3058 NULL,                                                   // #200
3059 NULL,                                                   // #201
3060 NULL,                                                   // #202
3061 NULL,                                                   // #203
3062 NULL,                                                   // #204
3063 NULL,                                                   // #205
3064 NULL,                                                   // #206
3065 NULL,                                                   // #207
3066 NULL,                                                   // #208
3067 NULL,                                                   // #209
3068 NULL,                                                   // #210
3069 NULL,                                                   // #211
3070 NULL,                                                   // #212
3071 NULL,                                                   // #213
3072 NULL,                                                   // #214
3073 NULL,                                                   // #215
3074 NULL,                                                   // #216
3075 NULL,                                                   // #217
3076 VM_bitshift,                                    // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3077 NULL,                                                   // #219
3078 NULL,                                                   // #220
3079 VM_strstrofs,                                   // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3080 VM_str2chr,                                             // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3081 VM_chr2str,                                             // #223 string(float c, ...) chr2str (FTE_STRINGS)
3082 VM_strconv,                                             // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3083 VM_strpad,                                              // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3084 VM_infoadd,                                             // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3085 VM_infoget,                                             // #227 string(string info, string key) infoget (FTE_STRINGS)
3086 VM_strncmp,                                             // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3087 VM_strncasecmp,                                 // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3088 VM_strncasecmp,                                 // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3089 NULL,                                                   // #231
3090 NULL,                                                   // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3091 NULL,                                                   // #233
3092 NULL,                                                   // #234
3093 NULL,                                                   // #235
3094 NULL,                                                   // #236
3095 NULL,                                                   // #237
3096 NULL,                                                   // #238
3097 NULL,                                                   // #239
3098 NULL,                                                   // #240
3099 NULL,                                                   // #241
3100 NULL,                                                   // #242
3101 NULL,                                                   // #243
3102 NULL,                                                   // #244
3103 NULL,                                                   // #245
3104 NULL,                                                   // #246
3105 NULL,                                                   // #247
3106 NULL,                                                   // #248
3107 NULL,                                                   // #249
3108 NULL,                                                   // #250
3109 NULL,                                                   // #251
3110 NULL,                                                   // #252
3111 NULL,                                                   // #253
3112 NULL,                                                   // #254
3113 NULL,                                                   // #255
3114 NULL,                                                   // #256
3115 NULL,                                                   // #257
3116 NULL,                                                   // #258
3117 NULL,                                                   // #259
3118 NULL,                                                   // #260
3119 NULL,                                                   // #261
3120 NULL,                                                   // #262
3121 NULL,                                                   // #263
3122 NULL,                                                   // #264
3123 NULL,                                                   // #265
3124 NULL,                                                   // #266
3125 NULL,                                                   // #267
3126 NULL,                                                   // #268
3127 NULL,                                                   // #269
3128 NULL,                                                   // #270
3129 NULL,                                                   // #271
3130 NULL,                                                   // #272
3131 NULL,                                                   // #273
3132 NULL,                                                   // #274
3133 NULL,                                                   // #275
3134 NULL,                                                   // #276
3135 NULL,                                                   // #277
3136 NULL,                                                   // #278
3137 NULL,                                                   // #279
3138 NULL,                                                   // #280
3139 NULL,                                                   // #281
3140 NULL,                                                   // #282
3141 NULL,                                                   // #283
3142 NULL,                                                   // #284
3143 NULL,                                                   // #285
3144 NULL,                                                   // #286
3145 NULL,                                                   // #287
3146 NULL,                                                   // #288
3147 NULL,                                                   // #289
3148 NULL,                                                   // #290
3149 NULL,                                                   // #291
3150 NULL,                                                   // #292
3151 NULL,                                                   // #293
3152 NULL,                                                   // #294
3153 NULL,                                                   // #295
3154 NULL,                                                   // #296
3155 NULL,                                                   // #297
3156 NULL,                                                   // #298
3157 NULL,                                                   // #299
3158 // CSQC range #300-#399
3159 VM_CL_R_ClearScene,                             // #300 void() clearscene (EXT_CSQC)
3160 VM_CL_R_AddEntities,                    // #301 void(float mask) addentities (EXT_CSQC)
3161 VM_CL_R_AddEntity,                              // #302 void(entity ent) addentity (EXT_CSQC)
3162 VM_CL_R_SetView,                                // #303 float(float property, ...) setproperty (EXT_CSQC)
3163 VM_CL_R_RenderScene,                    // #304 void() renderscene (EXT_CSQC)
3164 VM_CL_R_AddDynamicLight,                // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3165 VM_CL_R_PolygonBegin,                   // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3166 VM_CL_R_PolygonVertex,                  // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3167 VM_CL_R_PolygonEnd,                             // #308 void() R_EndPolygon
3168 NULL,                                                   // #309
3169 VM_CL_unproject,                                // #310 vector (vector v) cs_unproject (EXT_CSQC)
3170 VM_CL_project,                                  // #311 vector (vector v) cs_project (EXT_CSQC)
3171 NULL,                                                   // #312
3172 NULL,                                                   // #313
3173 NULL,                                                   // #314
3174 VM_drawline,                                    // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3175 VM_iscachedpic,                                 // #316 float(string name) iscachedpic (EXT_CSQC)
3176 VM_precache_pic,                                // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3177 VM_getimagesize,                                // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3178 VM_freepic,                                             // #319 void(string name) freepic (EXT_CSQC)
3179 VM_drawcharacter,                               // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3180 VM_drawstring,                                  // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3181 VM_drawpic,                                             // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3182 VM_drawfill,                                    // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3183 VM_drawsetcliparea,                             // #324 void(float x, float y, float width, float height) drawsetcliparea
3184 VM_drawresetcliparea,                   // #325 void(void) drawresetcliparea
3185 VM_drawcolorcodedstring,                // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3186 NULL,                                                   // #327 // FIXME add stringwidth() here?
3187 NULL,                                                   // #328 // FIXME add drawsubpic() here?
3188 NULL,                                                   // #329
3189 VM_CL_getstatf,                                 // #330 float(float stnum) getstatf (EXT_CSQC)
3190 VM_CL_getstati,                                 // #331 float(float stnum) getstati (EXT_CSQC)
3191 VM_CL_getstats,                                 // #332 string(float firststnum) getstats (EXT_CSQC)
3192 VM_CL_setmodelindex,                    // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3193 VM_CL_modelnameforindex,                // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3194 VM_CL_particleeffectnum,                // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3195 VM_CL_trailparticles,                   // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3196 VM_CL_pointparticles,                   // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3197 VM_centerprint,                                 // #338 void(string s, ...) centerprint (EXT_CSQC)
3198 VM_print,                                               // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3199 VM_keynumtostring,                              // #340 string(float keynum) keynumtostring (EXT_CSQC)
3200 VM_stringtokeynum,                              // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3201 VM_CL_getkeybind,                               // #342 string(float keynum) getkeybind (EXT_CSQC)
3202 VM_CL_setcursormode,                    // #343 void(float usecursor) setcursormode (EXT_CSQC)
3203 VM_getmousepos,                                 // #344 vector() getmousepos (EXT_CSQC)
3204 VM_CL_getinputstate,                    // #345 float(float framenum) getinputstate (EXT_CSQC)
3205 VM_CL_setsensitivityscale,              // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3206 VM_CL_runplayerphysics,                 // #347 void() runstandardplayerphysics (EXT_CSQC)
3207 VM_CL_getplayerkey,                             // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3208 VM_CL_isdemo,                                   // #349 float() isdemo (EXT_CSQC)
3209 VM_isserver,                                    // #350 float() isserver (EXT_CSQC)
3210 VM_CL_setlistener,                              // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3211 VM_CL_registercmd,                              // #352 void(string cmdname) registercommand (EXT_CSQC)
3212 VM_wasfreed,                                    // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3213 VM_CL_serverkey,                                // #354 string(string key) serverkey (EXT_CSQC)
3214 NULL,                                                   // #355
3215 NULL,                                                   // #356
3216 NULL,                                                   // #357
3217 NULL,                                                   // #358
3218 NULL,                                                   // #359
3219 VM_CL_ReadByte,                                 // #360 float() readbyte (EXT_CSQC)
3220 VM_CL_ReadChar,                                 // #361 float() readchar (EXT_CSQC)
3221 VM_CL_ReadShort,                                // #362 float() readshort (EXT_CSQC)
3222 VM_CL_ReadLong,                                 // #363 float() readlong (EXT_CSQC)
3223 VM_CL_ReadCoord,                                // #364 float() readcoord (EXT_CSQC)
3224 VM_CL_ReadAngle,                                // #365 float() readangle (EXT_CSQC)
3225 VM_CL_ReadString,                               // #366 string() readstring (EXT_CSQC)
3226 VM_CL_ReadFloat,                                // #367 float() readfloat (EXT_CSQC)
3227 NULL,                                           // #368
3228 NULL,                                                   // #369
3229 NULL,                                                   // #370
3230 NULL,                                                   // #371
3231 NULL,                                                   // #372
3232 NULL,                                                   // #373
3233 NULL,                                                   // #374
3234 NULL,                                                   // #375
3235 NULL,                                                   // #376
3236 NULL,                                                   // #377
3237 NULL,                                                   // #378
3238 NULL,                                                   // #379
3239 NULL,                                                   // #380
3240 NULL,                                                   // #381
3241 NULL,                                                   // #382
3242 NULL,                                                   // #383
3243 NULL,                                                   // #384
3244 NULL,                                                   // #385
3245 NULL,                                                   // #386
3246 NULL,                                                   // #387
3247 NULL,                                                   // #388
3248 NULL,                                                   // #389
3249 NULL,                                                   // #390
3250 NULL,                                                   // #391
3251 NULL,                                                   // #392
3252 NULL,                                                   // #393
3253 NULL,                                                   // #394
3254 NULL,                                                   // #395
3255 NULL,                                                   // #396
3256 NULL,                                                   // #397
3257 NULL,                                                   // #398
3258 NULL,                                                   // #399
3259 // LordHavoc's range #400-#499
3260 VM_CL_copyentity,                               // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3261 NULL,                                                   // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3262 VM_findchain,                                   // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3263 VM_findchainfloat,                              // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3264 VM_CL_effect,                                   // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3265 VM_CL_te_blood,                                 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3266 VM_CL_te_bloodshower,                   // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3267 VM_CL_te_explosionrgb,                  // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3268 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)
3269 VM_CL_te_particlerain,                  // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3270 VM_CL_te_particlesnow,                  // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3271 VM_CL_te_spark,                                 // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3272 VM_CL_te_gunshotquad,                   // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3273 VM_CL_te_spikequad,                             // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3274 VM_CL_te_superspikequad,                // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3275 VM_CL_te_explosionquad,                 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3276 VM_CL_te_smallflash,                    // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3277 VM_CL_te_customflash,                   // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3278 VM_CL_te_gunshot,                               // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3279 VM_CL_te_spike,                                 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3280 VM_CL_te_superspike,                    // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3281 VM_CL_te_explosion,                             // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3282 VM_CL_te_tarexplosion,                  // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3283 VM_CL_te_wizspike,                              // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3284 VM_CL_te_knightspike,                   // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3285 VM_CL_te_lavasplash,                    // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3286 VM_CL_te_teleport,                              // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3287 VM_CL_te_explosion2,                    // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3288 VM_CL_te_lightning1,                    // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3289 VM_CL_te_lightning2,                    // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3290 VM_CL_te_lightning3,                    // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3291 VM_CL_te_beam,                                  // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3292 VM_vectorvectors,                               // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3293 VM_CL_te_plasmaburn,                    // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3294 VM_CL_getsurfacenumpoints,              // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3295 VM_CL_getsurfacepoint,                  // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3296 VM_CL_getsurfacenormal,                 // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3297 VM_CL_getsurfacetexture,                // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3298 VM_CL_getsurfacenearpoint,              // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3299 VM_CL_getsurfaceclippedpoint,   // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3300 NULL,                                                   // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3301 VM_tokenize,                                    // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3302 VM_argv,                                                // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3303 VM_CL_setattachment,                    // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3304 VM_search_begin,                                // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3305 VM_search_end,                                  // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3306 VM_search_getsize,                              // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3307 VM_search_getfilename,                  // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3308 VM_cvar_string,                                 // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3309 VM_findflags,                                   // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3310 VM_findchainflags,                              // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3311 VM_CL_gettagindex,                              // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3312 VM_CL_gettaginfo,                               // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3313 NULL,                                                   // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3314 NULL,                                                   // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3315 NULL,                                                   // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3316 NULL,                                                   // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3317 VM_CL_te_flamejet,                              // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3318 NULL,                                                   // #458
3319 VM_ftoe,                                                // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3320 VM_buf_create,                                  // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3321 VM_buf_del,                                             // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3322 VM_buf_getsize,                                 // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3323 VM_buf_copy,                                    // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3324 VM_buf_sort,                                    // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3325 VM_buf_implode,                                 // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3326 VM_bufstr_get,                                  // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3327 VM_bufstr_set,                                  // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3328 VM_bufstr_add,                                  // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3329 VM_bufstr_free,                                 // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3330 NULL,                                                   // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3331 VM_asin,                                                // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3332 VM_acos,                                                // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3333 VM_atan,                                                // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3334 VM_atan2,                                               // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3335 VM_tan,                                                 // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3336 VM_strlennocol,                                 // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3337 VM_strdecolorize,                               // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3338 VM_strftime,                                    // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3339 VM_tokenizebyseparator,                 // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3340 VM_strtolower,                                  // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3341 VM_strtoupper,                                  // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3342 VM_cvar_defstring,                              // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3343 VM_CL_pointsound,                               // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3344 VM_strreplace,                                  // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3345 VM_strireplace,                                 // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3346 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3347 #ifdef SUPPORT_GECKO
3348 VM_gecko_create,                                        // #487
3349 VM_gecko_destroy,                                       // #488
3350 VM_gecko_navigate,                              // #489
3351 VM_gecko_keyevent,                              // #490
3352 VM_gecko_movemouse,                             // #491
3353 #else
3354 NULL,                                                                   // #487
3355 NULL,                                                                   // #488
3356 NULL,                                                                   // #489
3357 NULL,                                                                   // #490
3358 NULL,                                                                   // #491
3359 #endif
3360 NULL,                                                   // #492
3361 NULL,                                                   // #493
3362 NULL,                                                   // #494
3363 NULL,                                                   // #495
3364 NULL,                                                   // #496
3365 NULL,                                                   // #497
3366 NULL,                                                   // #498
3367 NULL,                                                   // #499
3368 };
3369
3370 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3371
3372 void VM_CL_Cmd_Init(void)
3373 {
3374         VM_Cmd_Init();
3375         // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3376         if(vm_polygons_initialized)
3377         {
3378                 Mem_FreePool(&vm_polygons_pool);
3379                 vm_polygons_initialized = false;
3380         }
3381 }
3382
3383 void VM_CL_Cmd_Reset(void)
3384 {
3385         VM_Cmd_Reset();
3386         if(vm_polygons_initialized)
3387         {
3388                 Mem_FreePool(&vm_polygons_pool);
3389                 vm_polygons_initialized = false;
3390         }
3391 }
3392