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