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