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