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