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