]> git.xonotic.org Git - xonotic/darkplaces.git/blob - clvm_cmds.c
common: Define DP_STATIC_ASSERT which wraps static_assert
[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 r_refdef_view_t csqc_original_r_refdef_view;
26 r_refdef_view_t csqc_main_r_refdef_view;
27
28 // #1 void(vector ang) makevectors
29 static void VM_CL_makevectors (prvm_prog_t *prog)
30 {
31         vec3_t angles, forward, right, up;
32         VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
33         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), angles);
34         AngleVectors(angles, forward, right, up);
35         VectorCopy(forward, PRVM_clientglobalvector(v_forward));
36         VectorCopy(right, PRVM_clientglobalvector(v_right));
37         VectorCopy(up, PRVM_clientglobalvector(v_up));
38 }
39
40 // #2 void(entity e, vector o) setorigin
41 static void VM_CL_setorigin (prvm_prog_t *prog)
42 {
43         prvm_edict_t    *e;
44         prvm_vec_t      *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(prog, "setorigin: can not modify world entity\n");
51                 return;
52         }
53         if (e->priv.required->free)
54         {
55                 VM_Warning(prog, "setorigin: can not modify free entity\n");
56                 return;
57         }
58         org = PRVM_G_VECTOR(OFS_PARM1);
59         VectorCopy (org, PRVM_clientedictvector(e, origin));
60         if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
61                 e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
62         CL_LinkEdict(e);
63 }
64
65 static void SetMinMaxSizePRVM (prvm_prog_t *prog, prvm_edict_t *e, prvm_vec_t *min, prvm_vec_t *max)
66 {
67         int             i;
68
69         for (i=0 ; i<3 ; i++)
70                 if (min[i] > max[i])
71                         prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
72
73         // set derived values
74         VectorCopy (min, PRVM_clientedictvector(e, mins));
75         VectorCopy (max, PRVM_clientedictvector(e, maxs));
76         VectorSubtract (max, min, PRVM_clientedictvector(e, size));
77
78         CL_LinkEdict (e);
79 }
80
81 static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, const vec_t *min, const vec_t *max)
82 {
83         prvm_vec3_t mins, maxs;
84         VectorCopy(min, mins);
85         VectorCopy(max, maxs);
86         SetMinMaxSizePRVM(prog, e, mins, maxs);
87 }
88
89 // #3 void(entity e, string m) setmodel
90 static void VM_CL_setmodel (prvm_prog_t *prog)
91 {
92         prvm_edict_t    *e;
93         const char              *m;
94         model_t *mod;
95         int                             i;
96
97         VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
98
99         e = PRVM_G_EDICT(OFS_PARM0);
100         PRVM_clientedictfloat(e, modelindex) = 0;
101         PRVM_clientedictstring(e, model) = 0;
102
103         m = PRVM_G_STRING(OFS_PARM1);
104         mod = NULL;
105         for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
106         {
107                 if (!strcmp(cl.csqc_model_precache[i]->name, m))
108                 {
109                         mod = cl.csqc_model_precache[i];
110                         PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name);
111                         PRVM_clientedictfloat(e, modelindex) = -(i+1);
112                         break;
113                 }
114         }
115
116         if( !mod ) {
117                 for (i = 0;i < MAX_MODELS;i++)
118                 {
119                         mod = cl.model_precache[i];
120                         if (mod && !strcmp(mod->name, m))
121                         {
122                                 PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name);
123                                 PRVM_clientedictfloat(e, modelindex) = i;
124                                 break;
125                         }
126                 }
127         }
128
129         if( mod ) {
130                 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
131                 // LadyHavoc: erm you broke it by commenting this out - setmodel must do setsize or else the qc can't find out the model size, and ssqc does this by necessity, consistency.
132                 SetMinMaxSize (prog, e, mod->normalmins, mod->normalmaxs);
133         }
134         else
135         {
136                 SetMinMaxSize (prog, e, vec3_origin, vec3_origin);
137                 VM_Warning(prog, "setmodel: model '%s' not precached\n", m);
138         }
139 }
140
141 // #4 void(entity e, vector min, vector max) setsize
142 static void VM_CL_setsize (prvm_prog_t *prog)
143 {
144         prvm_edict_t    *e;
145         vec3_t          mins, maxs;
146         VM_SAFEPARMCOUNT(3, VM_CL_setsize);
147
148         e = PRVM_G_EDICT(OFS_PARM0);
149         if (e == prog->edicts)
150         {
151                 VM_Warning(prog, "setsize: can not modify world entity\n");
152                 return;
153         }
154         if (e->priv.server->free)
155         {
156                 VM_Warning(prog, "setsize: can not modify free entity\n");
157                 return;
158         }
159         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
160         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
161
162         SetMinMaxSize( prog, e, mins, maxs );
163
164         CL_LinkEdict(e);
165 }
166
167 // #8 void(entity e, float chan, string samp, float volume, float atten[, float pitchchange[, float flags]]) sound
168 static void VM_CL_sound (prvm_prog_t *prog)
169 {
170         const char                      *sample;
171         int                                     channel;
172         prvm_edict_t            *entity;
173         float                           fvolume;
174         float                           attenuation;
175         float pitchchange;
176         float                           startposition;
177         int flags;
178         vec3_t                          org;
179
180         VM_SAFEPARMCOUNTRANGE(5, 7, VM_CL_sound);
181
182         entity = PRVM_G_EDICT(OFS_PARM0);
183         channel = (int)PRVM_G_FLOAT(OFS_PARM1);
184         sample = PRVM_G_STRING(OFS_PARM2);
185         fvolume = PRVM_G_FLOAT(OFS_PARM3);
186         attenuation = PRVM_G_FLOAT(OFS_PARM4);
187
188         if (fvolume < 0 || fvolume > 1)
189         {
190                 VM_Warning(prog, "VM_CL_sound: volume must be in range 0-1\n");
191                 return;
192         }
193
194         if (attenuation < 0 || attenuation > 4)
195         {
196                 VM_Warning(prog, "VM_CL_sound: attenuation must be in range 0-4\n");
197                 return;
198         }
199
200         if (prog->argc < 6)
201                 pitchchange = 0;
202         else
203                 pitchchange = PRVM_G_FLOAT(OFS_PARM5);
204
205         if (prog->argc < 7)
206                 flags = 0;
207         else
208         {
209                 // LadyHavoc: we only let the qc set certain flags, others are off-limits
210                 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
211         }
212
213         // sound_starttime exists instead of sound_startposition because in a
214         // networking sense you might not know when something is being received,
215         // so making sounds match up in sync would be impossible if relative
216         // position was sent
217         if (PRVM_clientglobalfloat(sound_starttime))
218                 startposition = cl.time - PRVM_clientglobalfloat(sound_starttime);
219         else
220                 startposition = 0;
221
222         if (!IS_CHAN(channel))
223         {
224                 VM_Warning(prog, "VM_CL_sound: channel must be in range 0-127\n");
225                 return;
226         }
227
228         CL_VM_GetEntitySoundOrigin(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), org);
229         S_StartSound_StartPosition_Flags(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), org, fvolume, attenuation, startposition, flags, pitchchange > 0.0f ? pitchchange * 0.01f : 1.0f);
230 }
231
232 // #483 void(vector origin, string sample, float volume, float attenuation) pointsound
233 static void VM_CL_pointsound(prvm_prog_t *prog)
234 {
235         const char                      *sample;
236         float                           fvolume;
237         float                           attenuation;
238         vec3_t                          org;
239
240         VM_SAFEPARMCOUNT(4, VM_CL_pointsound);
241
242         VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org);
243         sample = PRVM_G_STRING(OFS_PARM1);
244         fvolume = PRVM_G_FLOAT(OFS_PARM2);
245         attenuation = PRVM_G_FLOAT(OFS_PARM3);
246
247         if (fvolume < 0 || fvolume > 1)
248         {
249                 VM_Warning(prog, "VM_CL_pointsound: volume must be in range 0-1\n");
250                 return;
251         }
252
253         if (attenuation < 0 || attenuation > 4)
254         {
255                 VM_Warning(prog, "VM_CL_pointsound: attenuation must be in range 0-4\n");
256                 return;
257         }
258
259         // Send World Entity as Entity to Play Sound (for CSQC, that is MAX_EDICTS)
260         S_StartSound(MAX_EDICTS, 0, S_FindName(sample), org, fvolume, attenuation);
261 }
262
263 // #14 entity() spawn
264 static void VM_CL_spawn (prvm_prog_t *prog)
265 {
266         prvm_edict_t *ed;
267         ed = PRVM_ED_Alloc(prog);
268         VM_RETURN_EDICT(ed);
269 }
270
271 static void CL_VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace, int svent)
272 {
273         VM_SetTraceGlobals(prog, trace);
274         PRVM_clientglobalfloat(trace_networkentity) = svent;
275 }
276
277 #define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY)
278 #define CL_HitNetworkPlayers(move)     !((move) == MOVE_WORLDONLY || (move) == MOVE_NOMONSTERS)
279
280 // #16 void(vector v1, vector v2, float movetype, entity ignore) traceline
281 static void VM_CL_traceline (prvm_prog_t *prog)
282 {
283         vec3_t  v1, v2;
284         trace_t trace;
285         int             move, svent;
286         prvm_edict_t    *ent;
287
288 //      R_TimeReport("pretraceline");
289
290         VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
291
292         prog->xfunction->builtinsprofile += 30;
293
294         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
295         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
296         move = (int)PRVM_G_FLOAT(OFS_PARM2);
297         ent = PRVM_G_EDICT(OFS_PARM3);
298
299         if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
300                 prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
301
302         trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value, CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true, false);
303
304         CL_VM_SetTraceGlobals(prog, &trace, svent);
305 //      R_TimeReport("traceline");
306 }
307
308 /*
309 =================
310 VM_CL_tracebox
311
312 Used for use tracing and shot targeting
313 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
314 if the tryents flag is set.
315
316 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
317 =================
318 */
319 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
320 static void VM_CL_tracebox (prvm_prog_t *prog)
321 {
322         vec3_t  v1, v2, m1, m2;
323         trace_t trace;
324         int             move, svent;
325         prvm_edict_t    *ent;
326
327 //      R_TimeReport("pretracebox");
328         VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
329
330         prog->xfunction->builtinsprofile += 30;
331
332         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
333         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
334         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
335         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
336         move = (int)PRVM_G_FLOAT(OFS_PARM4);
337         ent = PRVM_G_EDICT(OFS_PARM5);
338
339         if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
340                 prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->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));
341
342         trace = CL_TraceBox(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value, CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
343
344         CL_VM_SetTraceGlobals(prog, &trace, svent);
345 //      R_TimeReport("tracebox");
346 }
347
348 static trace_t CL_Trace_Toss (prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
349 {
350         int i;
351         float gravity;
352         vec3_t start, end, mins, maxs, move;
353         vec3_t original_origin;
354         vec3_t original_velocity;
355         vec3_t original_angles;
356         vec3_t original_avelocity;
357         trace_t trace;
358
359         VectorCopy(PRVM_clientedictvector(tossent, origin)   , original_origin   );
360         VectorCopy(PRVM_clientedictvector(tossent, velocity) , original_velocity );
361         VectorCopy(PRVM_clientedictvector(tossent, angles)   , original_angles   );
362         VectorCopy(PRVM_clientedictvector(tossent, avelocity), original_avelocity);
363
364         gravity = PRVM_clientedictfloat(tossent, gravity);
365         if (!gravity)
366                 gravity = 1.0f;
367         gravity *= cl.movevars_gravity * 0.05;
368
369         for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
370         {
371                 PRVM_clientedictvector(tossent, velocity)[2] -= gravity;
372                 VectorMA (PRVM_clientedictvector(tossent, angles), 0.05, PRVM_clientedictvector(tossent, avelocity), PRVM_clientedictvector(tossent, angles));
373                 VectorScale (PRVM_clientedictvector(tossent, velocity), 0.05, move);
374                 VectorAdd (PRVM_clientedictvector(tossent, origin), move, end);
375                 VectorCopy(PRVM_clientedictvector(tossent, origin), start);
376                 VectorCopy(PRVM_clientedictvector(tossent, mins), mins);
377                 VectorCopy(PRVM_clientedictvector(tossent, maxs), maxs);
378                 trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value, true, true, NULL, true);
379                 VectorCopy (trace.endpos, PRVM_clientedictvector(tossent, origin));
380
381                 if (trace.fraction < 1)
382                         break;
383         }
384
385         VectorCopy(original_origin   , PRVM_clientedictvector(tossent, origin)   );
386         VectorCopy(original_velocity , PRVM_clientedictvector(tossent, velocity) );
387         VectorCopy(original_angles   , PRVM_clientedictvector(tossent, angles)   );
388         VectorCopy(original_avelocity, PRVM_clientedictvector(tossent, avelocity));
389
390         return trace;
391 }
392
393 static void VM_CL_tracetoss (prvm_prog_t *prog)
394 {
395         trace_t trace;
396         prvm_edict_t    *ent;
397         prvm_edict_t    *ignore;
398         int svent = 0;
399
400         prog->xfunction->builtinsprofile += 600;
401
402         VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
403
404         ent = PRVM_G_EDICT(OFS_PARM0);
405         if (ent == prog->edicts)
406         {
407                 VM_Warning(prog, "tracetoss: can not use world entity\n");
408                 return;
409         }
410         ignore = PRVM_G_EDICT(OFS_PARM1);
411
412         trace = CL_Trace_Toss (prog, ent, ignore, &svent);
413
414         CL_VM_SetTraceGlobals(prog, &trace, svent);
415 }
416
417
418 // #20 void(string s) precache_model
419 static void VM_CL_precache_model (prvm_prog_t *prog)
420 {
421         const char      *name;
422         int                     i;
423         model_t         *m;
424
425         VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
426
427         name = PRVM_G_STRING(OFS_PARM0);
428         for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
429         {
430                 if(!strcmp(cl.csqc_model_precache[i]->name, name))
431                 {
432                         PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
433                         return;
434                 }
435         }
436         PRVM_G_FLOAT(OFS_RETURN) = 0;
437         m = Mod_ForName(name, false, false, name[0] == '*' ? cl.model_name[1] : NULL);
438         if(m && m->loaded)
439         {
440                 for (i = 0;i < MAX_MODELS;i++)
441                 {
442                         if (!cl.csqc_model_precache[i])
443                         {
444                                 cl.csqc_model_precache[i] = (model_t*)m;
445                                 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
446                                 return;
447                         }
448                 }
449                 VM_Warning(prog, "VM_CL_precache_model: no free models\n");
450                 return;
451         }
452         VM_Warning(prog, "VM_CL_precache_model: model \"%s\" not found\n", name);
453 }
454
455 // #22 entity(vector org, float rad) findradius
456 static void VM_CL_findradius (prvm_prog_t *prog)
457 {
458         prvm_edict_t    *ent, *chain;
459         vec_t                   radius, radius2;
460         vec3_t                  org, eorg, mins, maxs;
461         int                             i, numtouchedicts;
462         static prvm_edict_t     *touchedicts[MAX_EDICTS];
463         int             chainfield;
464
465         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_findradius);
466
467         if(prog->argc == 3)
468                 chainfield = PRVM_G_INT(OFS_PARM2);
469         else
470                 chainfield = prog->fieldoffsets.chain;
471         if(chainfield < 0)
472                 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
473
474         chain = (prvm_edict_t *)prog->edicts;
475
476         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
477         radius = PRVM_G_FLOAT(OFS_PARM1);
478         radius2 = radius * radius;
479
480         mins[0] = org[0] - (radius + 1);
481         mins[1] = org[1] - (radius + 1);
482         mins[2] = org[2] - (radius + 1);
483         maxs[0] = org[0] + (radius + 1);
484         maxs[1] = org[1] + (radius + 1);
485         maxs[2] = org[2] + (radius + 1);
486         numtouchedicts = World_EntitiesInBox(&cl.world, mins, maxs, MAX_EDICTS, touchedicts);
487         if (numtouchedicts > MAX_EDICTS)
488         {
489                 // this never happens   //[515]: for what then ?
490                 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
491                 numtouchedicts = MAX_EDICTS;
492         }
493         for (i = 0;i < numtouchedicts;i++)
494         {
495                 ent = touchedicts[i];
496                 // Quake did not return non-solid entities but darkplaces does
497                 // (note: this is the reason you can't blow up fallen zombies)
498                 if (PRVM_clientedictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
499                         continue;
500                 // LadyHavoc: compare against bounding box rather than center so it
501                 // doesn't miss large objects, and use DotProduct instead of Length
502                 // for a major speedup
503                 VectorSubtract(org, PRVM_clientedictvector(ent, origin), eorg);
504                 if (sv_gameplayfix_findradiusdistancetobox.integer)
505                 {
506                         eorg[0] -= bound(PRVM_clientedictvector(ent, mins)[0], eorg[0], PRVM_clientedictvector(ent, maxs)[0]);
507                         eorg[1] -= bound(PRVM_clientedictvector(ent, mins)[1], eorg[1], PRVM_clientedictvector(ent, maxs)[1]);
508                         eorg[2] -= bound(PRVM_clientedictvector(ent, mins)[2], eorg[2], PRVM_clientedictvector(ent, maxs)[2]);
509                 }
510                 else
511                         VectorMAMAM(1, eorg, -0.5f, PRVM_clientedictvector(ent, mins), -0.5f, PRVM_clientedictvector(ent, maxs), eorg);
512                 if (DotProduct(eorg, eorg) < radius2)
513                 {
514                         PRVM_EDICTFIELDEDICT(ent, chainfield) = PRVM_EDICT_TO_PROG(chain);
515                         chain = ent;
516                 }
517         }
518
519         VM_RETURN_EDICT(chain);
520 }
521
522 // #34 float() droptofloor
523 static void VM_CL_droptofloor (prvm_prog_t *prog)
524 {
525         prvm_edict_t            *ent;
526         vec3_t                          start, end, mins, maxs;
527         trace_t                         trace;
528
529         VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
530
531         // assume failure if it returns early
532         PRVM_G_FLOAT(OFS_RETURN) = 0;
533
534         ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
535         if (ent == prog->edicts)
536         {
537                 VM_Warning(prog, "droptofloor: can not modify world entity\n");
538                 return;
539         }
540         if (ent->priv.server->free)
541         {
542                 VM_Warning(prog, "droptofloor: can not modify free entity\n");
543                 return;
544         }
545
546         VectorCopy(PRVM_clientedictvector(ent, origin), start);
547         VectorCopy(PRVM_clientedictvector(ent, mins), mins);
548         VectorCopy(PRVM_clientedictvector(ent, maxs), maxs);
549         VectorCopy(PRVM_clientedictvector(ent, origin), end);
550         end[2] -= 256;
551
552         trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, NULL, true);
553
554         if (trace.fraction != 1)
555         {
556                 VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin));
557                 PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) | FL_ONGROUND;
558                 PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
559                 PRVM_G_FLOAT(OFS_RETURN) = 1;
560                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
561 //              ent->priv.server->suspendedinairflag = true;
562         }
563 }
564
565 // #35 void(float style, string value) lightstyle
566 static void VM_CL_lightstyle (prvm_prog_t *prog)
567 {
568         int                     i;
569         const char      *c;
570
571         VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
572
573         i = (int)PRVM_G_FLOAT(OFS_PARM0);
574         c = PRVM_G_STRING(OFS_PARM1);
575         if (i >= cl.max_lightstyle)
576         {
577                 VM_Warning(prog, "VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
578                 return;
579         }
580         strlcpy (cl.lightstyle[i].map, c, sizeof (cl.lightstyle[i].map));
581         cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
582         cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
583 }
584
585 // #40 float(entity e) checkbottom
586 static void VM_CL_checkbottom (prvm_prog_t *prog)
587 {
588         static int              cs_yes, cs_no;
589         prvm_edict_t    *ent;
590         vec3_t                  mins, maxs, start, stop;
591         trace_t                 trace;
592         int                             x, y;
593         float                   mid, bottom;
594
595         VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
596         ent = PRVM_G_EDICT(OFS_PARM0);
597         PRVM_G_FLOAT(OFS_RETURN) = 0;
598
599         VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
600         VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
601
602 // if all of the points under the corners are solid world, don't bother
603 // with the tougher checks
604 // the corners must be within 16 of the midpoint
605         start[2] = mins[2] - 1;
606         for     (x=0 ; x<=1 ; x++)
607                 for     (y=0 ; y<=1 ; y++)
608                 {
609                         start[0] = x ? maxs[0] : mins[0];
610                         start[1] = y ? maxs[1] : mins[1];
611                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
612                                 goto realcheck;
613                 }
614
615         cs_yes++;
616         PRVM_G_FLOAT(OFS_RETURN) = true;
617         return;         // we got out easy
618
619 realcheck:
620         cs_no++;
621 //
622 // check it for real...
623 //
624         start[2] = mins[2];
625
626 // the midpoint must be within 16 of the bottom
627         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
628         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
629         stop[2] = start[2] - 2*sv_stepheight.value;
630         trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, NULL, true, false);
631
632         if (trace.fraction == 1.0)
633                 return;
634
635         mid = bottom = trace.endpos[2];
636
637 // the corners must be within 16 of the midpoint
638         for     (x=0 ; x<=1 ; x++)
639                 for     (y=0 ; y<=1 ; y++)
640                 {
641                         start[0] = stop[0] = x ? maxs[0] : mins[0];
642                         start[1] = stop[1] = y ? maxs[1] : mins[1];
643
644                         trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, NULL, true, false);
645
646                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
647                                 bottom = trace.endpos[2];
648                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
649                                 return;
650                 }
651
652         cs_yes++;
653         PRVM_G_FLOAT(OFS_RETURN) = true;
654 }
655
656 // #41 float(vector v) pointcontents
657 static void VM_CL_pointcontents (prvm_prog_t *prog)
658 {
659         vec3_t point;
660         VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
661         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
662         PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(CL_PointSuperContents(point));
663 }
664
665 // #48 void(vector o, vector d, float color, float count) particle
666 static void VM_CL_particle (prvm_prog_t *prog)
667 {
668         vec3_t org, dir;
669         int             count;
670         unsigned char   color;
671         VM_SAFEPARMCOUNT(4, VM_CL_particle);
672
673         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
674         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
675         color = (int)PRVM_G_FLOAT(OFS_PARM2);
676         count = (int)PRVM_G_FLOAT(OFS_PARM3);
677         CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
678 }
679
680 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
681 static void VM_CL_ambientsound (prvm_prog_t *prog)
682 {
683         vec3_t f;
684         sfx_t   *s;
685         VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
686         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f);
687         s = S_FindName(PRVM_G_STRING(OFS_PARM1));
688         S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
689 }
690
691 // #92 vector(vector org[, float lpflag]) getlight (DP_QC_GETLIGHT)
692 static void VM_CL_getlight (prvm_prog_t *prog)
693 {
694         vec3_t ambientcolor, diffusecolor, diffusenormal;
695         vec3_t p;
696         int flags = prog->argc >= 2 ? PRVM_G_FLOAT(OFS_PARM1) : LP_LIGHTMAP;
697
698         VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getlight);
699
700         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
701         R_CompleteLightPoint(ambientcolor, diffusecolor, diffusenormal, p, flags, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
702         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
703         if (PRVM_clientglobalvector(getlight_ambient))
704                 VectorCopy(ambientcolor, PRVM_clientglobalvector(getlight_ambient));
705         if (PRVM_clientglobalvector(getlight_diffuse))
706                 VectorCopy(diffusecolor, PRVM_clientglobalvector(getlight_diffuse));
707         if (PRVM_clientglobalvector(getlight_dir))
708                 VectorCopy(diffusenormal, PRVM_clientglobalvector(getlight_dir));
709 }
710
711 //============================================================================
712 //[515]: SCENE MANAGER builtins
713
714 extern cvar_t v_yshearing;
715 void CSQC_R_RecalcView (void)
716 {
717         extern matrix4x4_t viewmodelmatrix_nobob;
718         extern matrix4x4_t viewmodelmatrix_withbob;
719         Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], 1);
720         if (v_yshearing.value > 0)
721                 Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
722         Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
723         Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
724         Matrix4x4_Concat(&viewmodelmatrix_withbob, &r_refdef.view.matrix, &cl.csqc_viewmodelmatrixfromengine);
725 }
726
727 //#300 void() clearscene (EXT_CSQC)
728 static void VM_CL_R_ClearScene (prvm_prog_t *prog)
729 {
730         VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
731         // clear renderable entity and light lists
732         r_refdef.scene.numentities = 0;
733         r_refdef.scene.numlights = 0;
734         // restore the view settings to the values that VM_CL_UpdateView received from the client code
735         r_refdef.view = csqc_original_r_refdef_view;
736         // polygonbegin without draw2d arg has to guess
737         prog->polygonbegin_guess2d = false;
738         VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
739         VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
740         cl.csqc_vidvars.drawworld = r_drawworld.integer != 0;
741         cl.csqc_vidvars.drawenginesbar = false;
742         cl.csqc_vidvars.drawcrosshair = false;
743         CSQC_R_RecalcView();
744         // clear the CL_Mesh_Scene() used for CSQC polygons and engine effects, they will be added by CSQC_RelinkAllEntities and manually created by CSQC
745         CL_MeshEntities_Scene_Clear();
746 }
747
748 //#301 void(float mask) addentities (EXT_CSQC)
749 static void VM_CL_R_AddEntities (prvm_prog_t *prog)
750 {
751         double t = Sys_DirtyTime();
752         int                     i, drawmask;
753         prvm_edict_t *ed;
754         VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
755         drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
756         CSQC_RelinkAllEntities(drawmask);
757
758         PRVM_clientglobalfloat(time) = cl.time;
759         for(i=1;i<prog->num_edicts;i++)
760         {
761                 // so we can easily check if CSQC entity #edictnum is currently drawn
762                 cl.csqcrenderentities[i].entitynumber = 0;
763                 ed = &prog->edicts[i];
764                 if(ed->priv.required->free)
765                         continue;
766                 CSQC_Think(ed);
767                 if(ed->priv.required->free)
768                         continue;
769                 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
770                 CSQC_Predraw(ed);
771                 if(ed->priv.required->free)
772                         continue;
773                 if(!((int)PRVM_clientedictfloat(ed, drawmask) & drawmask))
774                         continue;
775                 CSQC_AddRenderEdict(ed, i);
776         }
777
778         // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
779         t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
780         prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
781 }
782
783 //#302 void(entity ent) addentity (EXT_CSQC)
784 static void VM_CL_R_AddEntity (prvm_prog_t *prog)
785 {
786         double t = Sys_DirtyTime();
787         VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
788         CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0), 0);
789         t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
790         prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
791 }
792
793 //#303 float(float property, ...) setproperty (EXT_CSQC)
794 //#303 float(float property) getproperty
795 //#303 vector(float property) getpropertyvec
796 //#309 float(float property) getproperty
797 //#309 vector(float property) getpropertyvec
798 // VorteX: make this function be able to return previously set property if new value is not given
799 static void VM_CL_R_SetView (prvm_prog_t *prog)
800 {
801         int             c;
802         prvm_vec_t      *f;
803         float   k;
804
805         VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_R_SetView);
806
807         c = (int)PRVM_G_FLOAT(OFS_PARM0);
808
809         // return value?
810         if (prog->argc < 2)
811         {
812                 switch(c)
813                 {
814                 case VF_MIN:
815                         VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.x, r_refdef.view.y, 0);
816                         break;
817                 case VF_MIN_X:
818                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.x;
819                         break;
820                 case VF_MIN_Y:
821                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.y;
822                         break;
823                 case VF_SIZE:
824                         VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.width, r_refdef.view.height, 0);
825                         break;
826                 case VF_SIZE_X:
827                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.width;
828                         break;
829                 case VF_SIZE_Y:
830                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.height;
831                         break;
832                 case VF_VIEWPORT:
833                         VM_Warning(prog, "VM_CL_R_GetView : VF_VIEWPORT can't be retrieved, use VF_MIN/VF_SIZE instead\n");
834                         break;
835                 case VF_FOV:
836                         VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.ortho_x, r_refdef.view.ortho_y, 0);
837                         break;
838                 case VF_FOVX:
839                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_x;
840                         break;
841                 case VF_FOVY:
842                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_y;
843                         break;
844                 case VF_ORIGIN:
845                         VectorCopy(cl.csqc_vieworigin, PRVM_G_VECTOR(OFS_RETURN));
846                         break;
847                 case VF_ORIGIN_X:
848                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[0];
849                         break;
850                 case VF_ORIGIN_Y:
851                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[1];
852                         break;
853                 case VF_ORIGIN_Z:
854                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[2];
855                         break;
856                 case VF_ANGLES:
857                         VectorCopy(cl.csqc_viewangles, PRVM_G_VECTOR(OFS_RETURN));
858                         break;
859                 case VF_ANGLES_X:
860                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[0];
861                         break;
862                 case VF_ANGLES_Y:
863                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[1];
864                         break;
865                 case VF_ANGLES_Z:
866                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[2];
867                         break;
868                 case VF_DRAWWORLD:
869                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawworld;
870                         break;
871                 case VF_DRAWENGINESBAR:
872                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawenginesbar;
873                         break;
874                 case VF_DRAWCROSSHAIR:
875                         PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawcrosshair;
876                         break;
877                 case VF_CL_VIEWANGLES:
878                         VectorCopy(cl.viewangles, PRVM_G_VECTOR(OFS_RETURN));;
879                         break;
880                 case VF_CL_VIEWANGLES_X:
881                         PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[0];
882                         break;
883                 case VF_CL_VIEWANGLES_Y:
884                         PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[1];
885                         break;
886                 case VF_CL_VIEWANGLES_Z:
887                         PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[2];
888                         break;
889                 case VF_PERSPECTIVE:
890                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.useperspective;
891                         break;
892                 case VF_CLEARSCREEN:
893                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.isoverlay;
894                         break;
895                 case VF_MAINVIEW:
896                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ismain;
897                         break;
898                 case VF_FOG_DENSITY:
899                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_density;
900                         break;
901                 case VF_FOG_COLOR:
902                         PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red;
903                         PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green;
904                         PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue;
905                         break;
906                 case VF_FOG_COLOR_R:
907                         PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red;
908                         break;
909                 case VF_FOG_COLOR_G:
910                         PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green;
911                         break;
912                 case VF_FOG_COLOR_B:
913                         PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue;
914                         break;
915                 case VF_FOG_ALPHA:
916                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_alpha;
917                         break;
918                 case VF_FOG_START:
919                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_start;
920                         break;
921                 case VF_FOG_END:
922                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_end;
923                         break;
924                 case VF_FOG_HEIGHT:
925                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_height;
926                         break;
927                 case VF_FOG_FADEDEPTH:
928                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_fadedepth;
929                         break;
930                 case VF_MINFPS_QUALITY:
931                         PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.quality;
932                         break;
933                 default:
934                         PRVM_G_FLOAT(OFS_RETURN) = 0;
935                         VM_Warning(prog, "VM_CL_R_GetView : unknown parm %i\n", c);
936                         return;
937                 }
938                 return;
939         }
940
941         f = PRVM_G_VECTOR(OFS_PARM1);
942         k = PRVM_G_FLOAT(OFS_PARM1);
943         switch(c)
944         {
945         case VF_MIN:
946                 r_refdef.view.x = (int)(f[0]);
947                 r_refdef.view.y = (int)(f[1]);
948                 DrawQ_RecalcView();
949                 break;
950         case VF_MIN_X:
951                 r_refdef.view.x = (int)(k);
952                 DrawQ_RecalcView();
953                 break;
954         case VF_MIN_Y:
955                 r_refdef.view.y = (int)(k);
956                 DrawQ_RecalcView();
957                 break;
958         case VF_SIZE:
959                 r_refdef.view.width = (int)(f[0]);
960                 r_refdef.view.height = (int)(f[1]);
961                 DrawQ_RecalcView();
962                 break;
963         case VF_SIZE_X:
964                 r_refdef.view.width = (int)(k);
965                 DrawQ_RecalcView();
966                 break;
967         case VF_SIZE_Y:
968                 r_refdef.view.height = (int)(k);
969                 DrawQ_RecalcView();
970                 break;
971         case VF_VIEWPORT:
972                 r_refdef.view.x = (int)(f[0]);
973                 r_refdef.view.y = (int)(f[1]);
974                 f = PRVM_G_VECTOR(OFS_PARM2);
975                 r_refdef.view.width = (int)(f[0]);
976                 r_refdef.view.height = (int)(f[1]);
977                 DrawQ_RecalcView();
978                 break;
979         case VF_FOV:
980                 r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
981                 r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
982                 break;
983         case VF_FOVX:
984                 r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
985                 break;
986         case VF_FOVY:
987                 r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
988                 break;
989         case VF_ORIGIN:
990                 VectorCopy(f, cl.csqc_vieworigin);
991                 CSQC_R_RecalcView();
992                 break;
993         case VF_ORIGIN_X:
994                 cl.csqc_vieworigin[0] = k;
995                 CSQC_R_RecalcView();
996                 break;
997         case VF_ORIGIN_Y:
998                 cl.csqc_vieworigin[1] = k;
999                 CSQC_R_RecalcView();
1000                 break;
1001         case VF_ORIGIN_Z:
1002                 cl.csqc_vieworigin[2] = k;
1003                 CSQC_R_RecalcView();
1004                 break;
1005         case VF_ANGLES:
1006                 VectorCopy(f, cl.csqc_viewangles);
1007                 CSQC_R_RecalcView();
1008                 break;
1009         case VF_ANGLES_X:
1010                 cl.csqc_viewangles[0] = k;
1011                 CSQC_R_RecalcView();
1012                 break;
1013         case VF_ANGLES_Y:
1014                 cl.csqc_viewangles[1] = k;
1015                 CSQC_R_RecalcView();
1016                 break;
1017         case VF_ANGLES_Z:
1018                 cl.csqc_viewangles[2] = k;
1019                 CSQC_R_RecalcView();
1020                 break;
1021         case VF_DRAWWORLD:
1022                 cl.csqc_vidvars.drawworld = ((k != 0) && r_drawworld.integer);
1023                 break;
1024         case VF_DRAWENGINESBAR:
1025                 cl.csqc_vidvars.drawenginesbar = k != 0;
1026                 break;
1027         case VF_DRAWCROSSHAIR:
1028                 cl.csqc_vidvars.drawcrosshair = k != 0;
1029                 break;
1030         case VF_CL_VIEWANGLES:
1031                 VectorCopy(f, cl.viewangles);
1032                 break;
1033         case VF_CL_VIEWANGLES_X:
1034                 cl.viewangles[0] = k;
1035                 break;
1036         case VF_CL_VIEWANGLES_Y:
1037                 cl.viewangles[1] = k;
1038                 break;
1039         case VF_CL_VIEWANGLES_Z:
1040                 cl.viewangles[2] = k;
1041                 break;
1042         case VF_PERSPECTIVE:
1043                 r_refdef.view.useperspective = k != 0;
1044                 break;
1045         case VF_CLEARSCREEN:
1046                 r_refdef.view.isoverlay = !k;
1047                 break;
1048         case VF_MAINVIEW:
1049                 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ismain;
1050                 break;
1051         case VF_FOG_DENSITY:
1052                 r_refdef.fog_density = k;
1053                 break;
1054         case VF_FOG_COLOR:
1055                 r_refdef.fog_red = f[0];
1056                 r_refdef.fog_green = f[1];
1057                 r_refdef.fog_blue = f[2];
1058                 break;
1059         case VF_FOG_COLOR_R:
1060                 r_refdef.fog_red = k;
1061                 break;
1062         case VF_FOG_COLOR_G:
1063                 r_refdef.fog_green = k;
1064                 break;
1065         case VF_FOG_COLOR_B:
1066                 r_refdef.fog_blue = k;
1067                 break;
1068         case VF_FOG_ALPHA:
1069                 r_refdef.fog_alpha = k;
1070                 break;
1071         case VF_FOG_START:
1072                 r_refdef.fog_start = k;
1073                 break;
1074         case VF_FOG_END:
1075                 r_refdef.fog_end = k;
1076                 break;
1077         case VF_FOG_HEIGHT:
1078                 r_refdef.fog_height = k;
1079                 break;
1080         case VF_FOG_FADEDEPTH:
1081                 r_refdef.fog_fadedepth = k;
1082                 break;
1083         case VF_MINFPS_QUALITY:
1084                 r_refdef.view.quality = k;
1085                 break;
1086         default:
1087                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1088                 VM_Warning(prog, "VM_CL_R_SetView : unknown parm %i\n", c);
1089                 return;
1090         }
1091         PRVM_G_FLOAT(OFS_RETURN) = 1;
1092 }
1093
1094 //#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC)
1095 static void VM_CL_R_AddDynamicLight (prvm_prog_t *prog)
1096 {
1097         double t = Sys_DirtyTime();
1098         vec3_t org;
1099         float radius = 300;
1100         vec3_t col;
1101         int style = -1;
1102         const char *cubemapname = NULL;
1103         int pflags = PFLAGS_CORONA | PFLAGS_FULLDYNAMIC;
1104         float coronaintensity = 1;
1105         float coronasizescale = 0.25;
1106         qbool castshadow = true;
1107         float ambientscale = 0;
1108         float diffusescale = 1;
1109         float specularscale = 1;
1110         matrix4x4_t matrix;
1111         vec3_t forward, left, up;
1112         VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight);
1113
1114         // if we've run out of dlights, just return
1115         if (r_refdef.scene.numlights >= MAX_DLIGHTS)
1116                 return;
1117
1118         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1119         radius = PRVM_G_FLOAT(OFS_PARM1);
1120         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), col);
1121         if (prog->argc >= 4)
1122         {
1123                 style = (int)PRVM_G_FLOAT(OFS_PARM3);
1124                 if (style >= MAX_LIGHTSTYLES)
1125                 {
1126                         Con_DPrintf("VM_CL_R_AddDynamicLight: out of bounds lightstyle index %i\n", style);
1127                         style = -1;
1128                 }
1129         }
1130         if (prog->argc >= 5)
1131                 cubemapname = PRVM_G_STRING(OFS_PARM4);
1132         if (prog->argc >= 6)
1133                 pflags = (int)PRVM_G_FLOAT(OFS_PARM5);
1134         coronaintensity = (pflags & PFLAGS_CORONA) != 0;
1135         castshadow = (pflags & PFLAGS_NOSHADOW) == 0;
1136
1137         VectorScale(PRVM_clientglobalvector(v_forward), radius, forward);
1138         VectorScale(PRVM_clientglobalvector(v_right), -radius, left);
1139         VectorScale(PRVM_clientglobalvector(v_up), radius, up);
1140         Matrix4x4_FromVectors(&matrix, forward, left, up, org);
1141
1142         R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1143         r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++;
1144         t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
1145         prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
1146 }
1147
1148 //============================================================================
1149
1150 //#310 vector (vector v) cs_unproject (EXT_CSQC)
1151 static void VM_CL_unproject (prvm_prog_t *prog)
1152 {
1153         vec3_t f;
1154         vec3_t temp;
1155         vec3_t result;
1156
1157         VM_SAFEPARMCOUNT(1, VM_CL_unproject);
1158         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f);
1159         VectorSet(temp,
1160                 f[2],
1161                 (-1.0 + 2.0 * (f[0] / vid_conwidth.integer)) * f[2] * -r_refdef.view.frustum_x,
1162                 (-1.0 + 2.0 * (f[1] / vid_conheight.integer)) * f[2] * -r_refdef.view.frustum_y);
1163         if(v_flipped.integer)
1164                 temp[1] = -temp[1];
1165         Matrix4x4_Transform(&r_refdef.view.matrix, temp, result);
1166         VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN));
1167 }
1168
1169 //#311 vector (vector v) cs_project (EXT_CSQC)
1170 static void VM_CL_project (prvm_prog_t *prog)
1171 {
1172         vec3_t f;
1173         vec3_t v;
1174         matrix4x4_t m;
1175
1176         VM_SAFEPARMCOUNT(1, VM_CL_project);
1177         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f);
1178         Matrix4x4_Invert_Full(&m, &r_refdef.view.matrix);
1179         Matrix4x4_Transform(&m, f, v);
1180         if(v_flipped.integer)
1181                 v[1] = -v[1];
1182         VectorSet(PRVM_G_VECTOR(OFS_RETURN),
1183                 vid_conwidth.integer * (0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x)),
1184                 vid_conheight.integer * (0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y)),
1185                 v[0]);
1186         // explanation:
1187         // after transforming, relative position to viewport (0..1) = 0.5 * (1 + v[2]/v[0]/-frustum_{x \or y})
1188         // as 2D drawing honors the viewport too, to get the same pixel, we simply multiply this by conwidth/height
1189 }
1190
1191 //=============================================================================
1192 // Draw builtins (client & menu)
1193
1194 /*
1195 ========================
1196 VM_drawline
1197
1198 void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags)
1199 ========================
1200 */
1201 void VM_drawline (prvm_prog_t *prog)
1202 {
1203         prvm_vec_t      *c1, *c2, *rgb;
1204         float   alpha, width;
1205         unsigned char   flags;
1206
1207         VM_SAFEPARMCOUNT(6, VM_drawline);
1208
1209         // polygonbegin without draw2d arg has to guess
1210         prog->polygonbegin_guess2d = true;
1211
1212         width   = PRVM_G_FLOAT(OFS_PARM0);
1213         c1              = PRVM_G_VECTOR(OFS_PARM1);
1214         c2              = PRVM_G_VECTOR(OFS_PARM2);
1215         rgb             = PRVM_G_VECTOR(OFS_PARM3);
1216         alpha   = PRVM_G_FLOAT(OFS_PARM4);
1217         flags   = (int)PRVM_G_FLOAT(OFS_PARM5);
1218         DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags);
1219 }
1220
1221 /*
1222 =========
1223 VM_iscachedpic
1224
1225 float   iscachedpic(string pic)
1226 =========
1227 */
1228 void VM_iscachedpic(prvm_prog_t *prog)
1229 {
1230         VM_SAFEPARMCOUNT(1,VM_iscachedpic);
1231
1232         // drawq hasnt such a function, thus always return true
1233         PRVM_G_FLOAT(OFS_RETURN) = false;
1234 }
1235
1236 /*
1237 =========
1238 VM_precache_pic
1239
1240 string  precache_pic(string pic)
1241 =========
1242 */
1243 #define PRECACHE_PIC_FROMWAD 1 /* FTEQW, not supported here */
1244 #define PRECACHE_PIC_NOTPERSISTENT 2
1245 //#define PRECACHE_PIC_NOCLAMP 4
1246 #define PRECACHE_PIC_MIPMAP 8
1247 void VM_precache_pic(prvm_prog_t *prog)
1248 {
1249         const char      *s;
1250         int flags = CACHEPICFLAG_FAILONMISSING;
1251
1252         VM_SAFEPARMCOUNTRANGE(1, 2, VM_precache_pic);
1253
1254         s = PRVM_G_STRING(OFS_PARM0);
1255         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1256         VM_CheckEmptyString(prog, s);
1257
1258         if(prog->argc >= 2)
1259         {
1260                 int f = PRVM_G_FLOAT(OFS_PARM1);
1261                 if(f & PRECACHE_PIC_NOTPERSISTENT)
1262                         flags |= CACHEPICFLAG_NOTPERSISTENT;
1263                 //if(f & PRECACHE_PIC_NOCLAMP)
1264                 //      flags |= CACHEPICFLAG_NOCLAMP;
1265                 if(f & PRECACHE_PIC_MIPMAP)
1266                         flags |= CACHEPICFLAG_MIPMAP;
1267         }
1268
1269         if( !Draw_IsPicLoaded(Draw_CachePic_Flags(s, flags | CACHEPICFLAG_QUIET)) )
1270                 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1271 }
1272
1273 /*
1274 =========
1275 VM_freepic
1276
1277 freepic(string s)
1278 =========
1279 */
1280 void VM_freepic(prvm_prog_t *prog)
1281 {
1282         const char *s;
1283
1284         VM_SAFEPARMCOUNT(1,VM_freepic);
1285
1286         s = PRVM_G_STRING(OFS_PARM0);
1287         VM_CheckEmptyString(prog, s);
1288
1289         Draw_FreePic(s);
1290 }
1291
1292 static void getdrawfontscale(prvm_prog_t *prog, float *sx, float *sy)
1293 {
1294         vec3_t v;
1295         *sx = *sy = 1;
1296         VectorCopy(PRVM_drawglobalvector(drawfontscale), v);
1297         if(VectorLength2(v) > 0)
1298         {
1299                 *sx = v[0];
1300                 *sy = v[1];
1301         }
1302 }
1303
1304 static dp_font_t *getdrawfont(prvm_prog_t *prog)
1305 {
1306         int f = (int) PRVM_drawglobalfloat(drawfont);
1307         if(f < 0 || f >= dp_fonts.maxsize)
1308                 return FONT_DEFAULT;
1309         return &dp_fonts.f[f];
1310 }
1311
1312 /*
1313 =========
1314 VM_drawcharacter
1315
1316 float   drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
1317 =========
1318 */
1319 void VM_drawcharacter(prvm_prog_t *prog)
1320 {
1321         prvm_vec_t *pos,*scale,*rgb;
1322         char   character;
1323         int flag;
1324         float sx, sy;
1325         VM_SAFEPARMCOUNT(6,VM_drawcharacter);
1326
1327         // polygonbegin without draw2d arg has to guess
1328         prog->polygonbegin_guess2d = true;
1329
1330         character = (char) PRVM_G_FLOAT(OFS_PARM1);
1331         if(character == 0)
1332         {
1333                 PRVM_G_FLOAT(OFS_RETURN) = -1;
1334                 VM_Warning(prog, "VM_drawcharacter: %s passed null character !\n",prog->name);
1335                 return;
1336         }
1337
1338         pos = PRVM_G_VECTOR(OFS_PARM0);
1339         scale = PRVM_G_VECTOR(OFS_PARM2);
1340         rgb = PRVM_G_VECTOR(OFS_PARM3);
1341         flag = (int)PRVM_G_FLOAT(OFS_PARM5);
1342
1343         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1344         {
1345                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1346                 VM_Warning(prog, "VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1347                 return;
1348         }
1349
1350         if(pos[2] || scale[2])
1351                 VM_Warning(prog, "VM_drawcharacter: z value%c from %s discarded\n",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
1352
1353         if(!scale[0] || !scale[1])
1354         {
1355                 PRVM_G_FLOAT(OFS_RETURN) = -3;
1356                 VM_Warning(prog, "VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
1357                 return;
1358         }
1359
1360         getdrawfontscale(prog, &sx, &sy);
1361         DrawQ_String_Scale(pos[0], pos[1], &character, 1, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog));
1362         PRVM_G_FLOAT(OFS_RETURN) = 1;
1363 }
1364
1365 /*
1366 =========
1367 VM_drawstring
1368
1369 float   drawstring(vector position, string text, vector scale, vector rgb, float alpha[, float flag])
1370 =========
1371 */
1372 void VM_drawstring(prvm_prog_t *prog)
1373 {
1374         prvm_vec_t *pos,*scale,*rgb;
1375         const char  *string;
1376         int flag = 0;
1377         float sx, sy;
1378         VM_SAFEPARMCOUNTRANGE(5,6,VM_drawstring);
1379
1380         // polygonbegin without draw2d arg has to guess
1381         prog->polygonbegin_guess2d = true;
1382
1383         string = PRVM_G_STRING(OFS_PARM1);
1384         pos = PRVM_G_VECTOR(OFS_PARM0);
1385         scale = PRVM_G_VECTOR(OFS_PARM2);
1386         rgb = PRVM_G_VECTOR(OFS_PARM3);
1387         if (prog->argc >= 6)
1388                 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
1389
1390         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1391         {
1392                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1393                 VM_Warning(prog, "VM_drawstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1394                 return;
1395         }
1396
1397         if(!scale[0] || !scale[1])
1398         {
1399                 PRVM_G_FLOAT(OFS_RETURN) = -3;
1400                 VM_Warning(prog, "VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
1401                 return;
1402         }
1403
1404         if(pos[2] || scale[2])
1405                 VM_Warning(prog, "VM_drawstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
1406
1407         getdrawfontscale(prog, &sx, &sy);
1408         DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog));
1409         //Font_DrawString(pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true);
1410         PRVM_G_FLOAT(OFS_RETURN) = 1;
1411 }
1412
1413 /*
1414 =========
1415 VM_drawcolorcodedstring
1416
1417 float   drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag)
1418 /
1419 float   drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
1420 =========
1421 */
1422 void VM_drawcolorcodedstring(prvm_prog_t *prog)
1423 {
1424         prvm_vec_t *pos, *scale;
1425         const char  *string;
1426         int flag;
1427         vec3_t rgb;
1428         float sx, sy, alpha;
1429
1430         VM_SAFEPARMCOUNTRANGE(5,6,VM_drawcolorcodedstring);
1431
1432         // polygonbegin without draw2d arg has to guess
1433         prog->polygonbegin_guess2d = true;
1434
1435         if (prog->argc == 6) // full 6 parms, like normal drawstring
1436         {
1437                 pos = PRVM_G_VECTOR(OFS_PARM0);
1438                 string = PRVM_G_STRING(OFS_PARM1);
1439                 scale = PRVM_G_VECTOR(OFS_PARM2);
1440                 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), rgb); 
1441                 alpha = PRVM_G_FLOAT(OFS_PARM4);
1442                 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
1443         }
1444         else
1445         {
1446                 pos = PRVM_G_VECTOR(OFS_PARM0);
1447                 string = PRVM_G_STRING(OFS_PARM1);
1448                 scale = PRVM_G_VECTOR(OFS_PARM2);
1449                 rgb[0] = 1.0;
1450                 rgb[1] = 1.0;
1451                 rgb[2] = 1.0;
1452                 alpha = PRVM_G_FLOAT(OFS_PARM3);
1453                 flag = (int)PRVM_G_FLOAT(OFS_PARM4);
1454         }
1455
1456         if(flag < DRAWFLAG_NORMAL || flag >= DRAWFLAG_NUMFLAGS)
1457         {
1458                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1459                 VM_Warning(prog, "VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1460                 return;
1461         }
1462
1463         if(!scale[0] || !scale[1])
1464         {
1465                 PRVM_G_FLOAT(OFS_RETURN) = -3;
1466                 VM_Warning(prog, "VM_drawcolorcodedstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
1467                 return;
1468         }
1469
1470         if(pos[2] || scale[2])
1471                 VM_Warning(prog, "VM_drawcolorcodedstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
1472
1473         getdrawfontscale(prog, &sx, &sy);
1474         DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], alpha, flag, NULL, false, getdrawfont(prog));
1475         if (prog->argc == 6) // also return vector of last color
1476                 VectorCopy(DrawQ_Color, PRVM_G_VECTOR(OFS_RETURN));
1477         else
1478                 PRVM_G_FLOAT(OFS_RETURN) = 1;
1479 }
1480 /*
1481 =========
1482 VM_stringwidth
1483
1484 float   stringwidth(string text, float allowColorCodes, float size)
1485 =========
1486 */
1487 void VM_stringwidth(prvm_prog_t *prog)
1488 {
1489         const char  *string;
1490         vec2_t szv;
1491         float mult; // sz is intended font size so we can later add freetype support, mult is font size multiplier in pixels per character cell
1492         int colors;
1493         float sx, sy;
1494         size_t maxlen = 0;
1495         VM_SAFEPARMCOUNTRANGE(2, 3, VM_stringwidth);
1496
1497         getdrawfontscale(prog, &sx, &sy);
1498         if(prog->argc == 3)
1499         {
1500                 Vector2Copy(PRVM_G_VECTOR(OFS_PARM2), szv);
1501                 mult = 1;
1502         }
1503         else
1504         {
1505                 // we want the width for 8x8 font size, divided by 8
1506                 Vector2Set(szv, 8, 8);
1507                 mult = 0.125;
1508                 // to make sure snapping is turned off, ALWAYS use a nontrivial scale in this case
1509                 if(sx >= 0.9 && sx <= 1.1)
1510                 {
1511                         mult *= 2;
1512                         sx /= 2;
1513                         sy /= 2;
1514                 }
1515         }
1516
1517         string = PRVM_G_STRING(OFS_PARM0);
1518         colors = (int)PRVM_G_FLOAT(OFS_PARM1);
1519
1520         PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth_UntilWidth_TrackColors_Scale(string, &maxlen, szv[0], szv[1], sx, sy, NULL, !colors, getdrawfont(prog), 1000000000) * mult;
1521 /*
1522         if(prog->argc == 3)
1523         {
1524                 mult = sz = PRVM_G_FLOAT(OFS_PARM2);
1525         }
1526         else
1527         {
1528                 sz = 8;
1529                 mult = 1;
1530         }
1531
1532         string = PRVM_G_STRING(OFS_PARM0);
1533         colors = (int)PRVM_G_FLOAT(OFS_PARM1);
1534
1535         PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth(string, 0, !colors, getdrawfont()) * mult; // 1x1 characters, don't actually draw
1536 */
1537 }
1538
1539 /*
1540 =========
1541 VM_findfont
1542
1543 float findfont(string s)
1544 =========
1545 */
1546
1547 static float getdrawfontnum(const char *fontname)
1548 {
1549         int i;
1550
1551         for(i = 0; i < dp_fonts.maxsize; ++i)
1552                 if(!strcmp(dp_fonts.f[i].title, fontname))
1553                         return i;
1554         return -1;
1555 }
1556
1557 void VM_findfont(prvm_prog_t *prog)
1558 {
1559         VM_SAFEPARMCOUNT(1,VM_findfont);
1560         PRVM_G_FLOAT(OFS_RETURN) = getdrawfontnum(PRVM_G_STRING(OFS_PARM0));
1561 }
1562
1563 /*
1564 =========
1565 VM_loadfont
1566
1567 float loadfont(string fontname, string fontmaps, string sizes, float slot)
1568 =========
1569 */
1570
1571 void VM_loadfont(prvm_prog_t *prog)
1572 {
1573         const char *fontname, *filelist, *sizes, *c, *cm;
1574         char mainfont[MAX_QPATH];
1575         int i, numsizes;
1576         float sz, scale, voffset;
1577         dp_font_t *f;
1578
1579         VM_SAFEPARMCOUNTRANGE(3,6,VM_loadfont);
1580
1581         fontname = PRVM_G_STRING(OFS_PARM0);
1582         if (!fontname[0])
1583                 fontname = "default";
1584
1585         filelist = PRVM_G_STRING(OFS_PARM1);
1586         if (!filelist[0])
1587                 filelist = "gfx/conchars";
1588
1589         sizes = PRVM_G_STRING(OFS_PARM2);
1590         if (!sizes[0])
1591                 sizes = "10";
1592
1593         // find a font
1594         f = NULL;
1595         if (prog->argc >= 4)
1596         {
1597                 i = PRVM_G_FLOAT(OFS_PARM3);
1598                 if (i >= 0 && i < dp_fonts.maxsize)
1599                 {
1600                         f = &dp_fonts.f[i];
1601                         strlcpy(f->title, fontname, sizeof(f->title)); // replace name
1602                 }
1603         }
1604         if (!f)
1605                 f = FindFont(fontname, true);
1606         if (!f)
1607         {
1608                 PRVM_G_FLOAT(OFS_RETURN) = -1;
1609                 return; // something go wrong
1610         }
1611
1612         memset(f->fallbacks, 0, sizeof(f->fallbacks));
1613         memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
1614
1615         // first font is handled "normally"
1616         c = strchr(filelist, ':');
1617         cm = strchr(filelist, ',');
1618         if(c && (!cm || c < cm))
1619                 f->req_face = atoi(c+1);
1620         else
1621         {
1622                 f->req_face = 0;
1623                 c = cm;
1624         }
1625         if(!c || (c - filelist) > MAX_QPATH)
1626                 strlcpy(mainfont, filelist, sizeof(mainfont));
1627         else
1628         {
1629                 memcpy(mainfont, filelist, c - filelist);
1630                 mainfont[c - filelist] = 0;
1631         }
1632
1633         // handle fallbacks
1634         for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
1635         {
1636                 c = strchr(filelist, ',');
1637                 if(!c)
1638                         break;
1639                 filelist = c + 1;
1640                 if(!*filelist)
1641                         break;
1642                 c = strchr(filelist, ':');
1643                 cm = strchr(filelist, ',');
1644                 if(c && (!cm || c < cm))
1645                         f->fallback_faces[i] = atoi(c+1);
1646                 else
1647                 {
1648                         f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
1649                         c = cm;
1650                 }
1651                 if(!c || (c-filelist) > MAX_QPATH)
1652                 {
1653                         strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
1654                 }
1655                 else
1656                 {
1657                         memcpy(f->fallbacks[i], filelist, c - filelist);
1658                         f->fallbacks[i][c - filelist] = 0;
1659                 }
1660         }
1661
1662         // handle sizes
1663         for(i = 0; i < MAX_FONT_SIZES; ++i)
1664                 f->req_sizes[i] = -1;
1665         for (numsizes = 0,c = sizes;;)
1666         {
1667                 if (!COM_ParseToken_VM_Tokenize(&c, 0))
1668                         break;
1669                 sz = atof(com_token);
1670                 // detect crap size
1671                 if (sz < 0.001f || sz > 1000.0f)
1672                 {
1673                         VM_Warning(prog, "VM_loadfont: crap size %s", com_token);
1674                         continue;
1675                 }
1676                 // check overflow
1677                 if (numsizes == MAX_FONT_SIZES)
1678                 {
1679                         VM_Warning(prog, "VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES);
1680                         break;
1681                 }
1682                 f->req_sizes[numsizes] = sz;
1683                 numsizes++;
1684         }
1685
1686         // additional scale/hoffset parms
1687         scale = 1;
1688         voffset = 0;
1689         if (prog->argc >= 5)
1690         {
1691                 scale = PRVM_G_FLOAT(OFS_PARM4);
1692                 if (scale <= 0)
1693                         scale = 1;
1694         }
1695         if (prog->argc >= 6)
1696                 voffset = PRVM_G_FLOAT(OFS_PARM5);
1697
1698         // load
1699         LoadFont(true, mainfont, f, scale, voffset);
1700
1701         // return index of loaded font
1702         PRVM_G_FLOAT(OFS_RETURN) = (f - dp_fonts.f);
1703 }
1704
1705 /*
1706 =========
1707 VM_drawpic
1708
1709 float   drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
1710 =========
1711 */
1712 void VM_drawpic(prvm_prog_t *prog)
1713 {
1714         const char *picname;
1715         prvm_vec_t *size, *pos, *rgb;
1716         int flag = 0;
1717
1718         VM_SAFEPARMCOUNTRANGE(5,6,VM_drawpic);
1719
1720         // polygonbegin without draw2d arg has to guess
1721         prog->polygonbegin_guess2d = true;
1722
1723         picname = PRVM_G_STRING(OFS_PARM1);
1724         VM_CheckEmptyString(prog, picname);
1725
1726         // is pic cached ? no function yet for that
1727         if(!1)
1728         {
1729                 PRVM_G_FLOAT(OFS_RETURN) = -4;
1730                 VM_Warning(prog, "VM_drawpic: %s: %s not cached !\n", prog->name, picname);
1731                 return;
1732         }
1733
1734         pos = PRVM_G_VECTOR(OFS_PARM0);
1735         size = PRVM_G_VECTOR(OFS_PARM2);
1736         rgb = PRVM_G_VECTOR(OFS_PARM3);
1737         if (prog->argc >= 6)
1738                 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
1739
1740         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1741         {
1742                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1743                 VM_Warning(prog, "VM_drawpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1744                 return;
1745         }
1746
1747         if(pos[2] || size[2])
1748                 VM_Warning(prog, "VM_drawpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
1749
1750         DrawQ_Pic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
1751         PRVM_G_FLOAT(OFS_RETURN) = 1;
1752 }
1753 /*
1754 =========
1755 VM_drawrotpic
1756
1757 float   drawrotpic(vector position, string pic, vector size, vector org, float angle, vector rgb, float alpha, float flag)
1758 =========
1759 */
1760 void VM_drawrotpic(prvm_prog_t *prog)
1761 {
1762         const char *picname;
1763         prvm_vec_t *size, *pos, *org, *rgb;
1764         int flag;
1765
1766         VM_SAFEPARMCOUNT(8,VM_drawrotpic);
1767
1768         // polygonbegin without draw2d arg has to guess
1769         prog->polygonbegin_guess2d = true;
1770
1771         picname = PRVM_G_STRING(OFS_PARM1);
1772         VM_CheckEmptyString(prog, picname);
1773
1774         // is pic cached ? no function yet for that
1775         if(!1)
1776         {
1777                 PRVM_G_FLOAT(OFS_RETURN) = -4;
1778                 VM_Warning(prog, "VM_drawrotpic: %s: %s not cached !\n", prog->name, picname);
1779                 return;
1780         }
1781
1782         pos = PRVM_G_VECTOR(OFS_PARM0);
1783         size = PRVM_G_VECTOR(OFS_PARM2);
1784         org = PRVM_G_VECTOR(OFS_PARM3);
1785         rgb = PRVM_G_VECTOR(OFS_PARM5);
1786         flag = (int) PRVM_G_FLOAT(OFS_PARM7);
1787
1788         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1789         {
1790                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1791                 VM_Warning(prog, "VM_drawrotpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1792                 return;
1793         }
1794
1795         if(pos[2] || size[2] || org[2])
1796                 VM_Warning(prog, "VM_drawrotpic: z value from pos/size/org discarded\n");
1797
1798         DrawQ_RotPic(pos[0], pos[1], Draw_CachePic_Flags(picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], org[0], org[1], PRVM_G_FLOAT(OFS_PARM4), rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM6), flag);
1799         PRVM_G_FLOAT(OFS_RETURN) = 1;
1800 }
1801 /*
1802 =========
1803 VM_drawsubpic
1804
1805 float   drawsubpic(vector position, vector size, string pic, vector srcPos, vector srcSize, vector rgb, float alpha, float flag)
1806
1807 =========
1808 */
1809 void VM_drawsubpic(prvm_prog_t *prog)
1810 {
1811         const char *picname;
1812         prvm_vec_t *size, *pos, *rgb, *srcPos, *srcSize, alpha;
1813         int flag;
1814
1815         VM_SAFEPARMCOUNT(8,VM_drawsubpic);
1816
1817         // polygonbegin without draw2d arg has to guess
1818         prog->polygonbegin_guess2d = true;
1819
1820         picname = PRVM_G_STRING(OFS_PARM2);
1821         VM_CheckEmptyString(prog, picname);
1822
1823         // is pic cached ? no function yet for that
1824         if(!1)
1825         {
1826                 PRVM_G_FLOAT(OFS_RETURN) = -4;
1827                 VM_Warning(prog, "VM_drawsubpic: %s: %s not cached !\n", prog->name, picname);
1828                 return;
1829         }
1830
1831         pos = PRVM_G_VECTOR(OFS_PARM0);
1832         size = PRVM_G_VECTOR(OFS_PARM1);
1833         srcPos = PRVM_G_VECTOR(OFS_PARM3);
1834         srcSize = PRVM_G_VECTOR(OFS_PARM4);
1835         rgb = PRVM_G_VECTOR(OFS_PARM5);
1836         alpha = PRVM_G_FLOAT(OFS_PARM6);
1837         flag = (int) PRVM_G_FLOAT(OFS_PARM7);
1838
1839         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1840         {
1841                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1842                 VM_Warning(prog, "VM_drawsubpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1843                 return;
1844         }
1845
1846         if(pos[2] || size[2])
1847                 VM_Warning(prog, "VM_drawsubpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
1848
1849         DrawQ_SuperPic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT),
1850                 size[0], size[1],
1851                 srcPos[0],              srcPos[1],              rgb[0], rgb[1], rgb[2], alpha,
1852                 srcPos[0] + srcSize[0], srcPos[1],              rgb[0], rgb[1], rgb[2], alpha,
1853                 srcPos[0],              srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha,
1854                 srcPos[0] + srcSize[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha,
1855                 flag);
1856         PRVM_G_FLOAT(OFS_RETURN) = 1;
1857 }
1858
1859 /*
1860 =========
1861 VM_drawfill
1862
1863 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
1864 =========
1865 */
1866 void VM_drawfill(prvm_prog_t *prog)
1867 {
1868         prvm_vec_t *size, *pos, *rgb;
1869         int flag;
1870
1871         VM_SAFEPARMCOUNT(5,VM_drawfill);
1872
1873         // polygonbegin without draw2d arg has to guess
1874         prog->polygonbegin_guess2d = true;
1875
1876         pos = PRVM_G_VECTOR(OFS_PARM0);
1877         size = PRVM_G_VECTOR(OFS_PARM1);
1878         rgb = PRVM_G_VECTOR(OFS_PARM2);
1879         flag = (int) PRVM_G_FLOAT(OFS_PARM4);
1880
1881         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1882         {
1883                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1884                 VM_Warning(prog, "VM_drawfill: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1885                 return;
1886         }
1887
1888         if(pos[2] || size[2])
1889                 VM_Warning(prog, "VM_drawfill: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
1890
1891         DrawQ_Fill(pos[0], pos[1], size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
1892         PRVM_G_FLOAT(OFS_RETURN) = 1;
1893 }
1894
1895 /*
1896 =========
1897 VM_drawsetcliparea
1898
1899 drawsetcliparea(float x, float y, float width, float height)
1900 =========
1901 */
1902 void VM_drawsetcliparea(prvm_prog_t *prog)
1903 {
1904         float x,y,w,h;
1905         VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
1906
1907         // polygonbegin without draw2d arg has to guess
1908         prog->polygonbegin_guess2d = true;
1909
1910         x = bound(0, PRVM_G_FLOAT(OFS_PARM0), vid_conwidth.integer);
1911         y = bound(0, PRVM_G_FLOAT(OFS_PARM1), vid_conheight.integer);
1912         w = bound(0, PRVM_G_FLOAT(OFS_PARM2) + PRVM_G_FLOAT(OFS_PARM0) - x, (vid_conwidth.integer  - x));
1913         h = bound(0, PRVM_G_FLOAT(OFS_PARM3) + PRVM_G_FLOAT(OFS_PARM1) - y, (vid_conheight.integer - y));
1914
1915         DrawQ_SetClipArea(x, y, w, h);
1916 }
1917
1918 /*
1919 =========
1920 VM_drawresetcliparea
1921
1922 drawresetcliparea()
1923 =========
1924 */
1925 void VM_drawresetcliparea(prvm_prog_t *prog)
1926 {
1927         VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
1928
1929         // polygonbegin without draw2d arg has to guess
1930         prog->polygonbegin_guess2d = true;
1931
1932         DrawQ_ResetClipArea();
1933 }
1934
1935 /*
1936 =========
1937 VM_getimagesize
1938
1939 vector  getimagesize(string pic)
1940 =========
1941 */
1942 void VM_getimagesize(prvm_prog_t *prog)
1943 {
1944         const char *p;
1945         cachepic_t *pic;
1946
1947         VM_SAFEPARMCOUNT(1,VM_getimagesize);
1948
1949         p = PRVM_G_STRING(OFS_PARM0);
1950         VM_CheckEmptyString(prog, p);
1951
1952         pic = Draw_CachePic_Flags (p, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOTPERSISTENT);
1953         if (!Draw_IsPicLoaded(pic))
1954         {
1955                 PRVM_G_VECTOR(OFS_RETURN)[0] = 0;
1956                 PRVM_G_VECTOR(OFS_RETURN)[1] = 0;
1957         }
1958         else
1959         {
1960                 PRVM_G_VECTOR(OFS_RETURN)[0] = Draw_GetPicWidth(pic);
1961                 PRVM_G_VECTOR(OFS_RETURN)[1] = Draw_GetPicHeight(pic);
1962         }
1963         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
1964 }
1965
1966 //#330 float(float stnum) getstatf (EXT_CSQC)
1967 static void VM_CL_getstatf (prvm_prog_t *prog)
1968 {
1969         int i;
1970         union
1971         {
1972                 float f;
1973                 int l;
1974         }dat;
1975         VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
1976         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1977         if(i < 0 || i >= MAX_CL_STATS)
1978         {
1979                 VM_Warning(prog, "VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
1980                 return;
1981         }
1982         dat.l = cl.stats[i];
1983         PRVM_G_FLOAT(OFS_RETURN) =  dat.f;
1984 }
1985
1986 //#331 float(float stnum) getstati (EXT_CSQC)
1987 static void VM_CL_getstati (prvm_prog_t *prog)
1988 {
1989         int i, index;
1990         int firstbit, bitcount;
1991
1992         VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
1993
1994         index = (int)PRVM_G_FLOAT(OFS_PARM0);
1995         if (prog->argc > 1)
1996         {
1997                 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
1998                 if (prog->argc > 2)
1999                         bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
2000                 else
2001                         bitcount = 1;
2002         }
2003         else
2004         {
2005                 firstbit = 0;
2006                 bitcount = 32;
2007         }
2008
2009         if(index < 0 || index >= MAX_CL_STATS)
2010         {
2011                 VM_Warning(prog, "VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
2012                 return;
2013         }
2014         i = cl.stats[index];
2015         if (bitcount != 32)     //32 causes the mask to overflow, so there's nothing to subtract from.
2016                 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
2017         PRVM_G_FLOAT(OFS_RETURN) = i;
2018 }
2019
2020 //#332 string(float firststnum) getstats (EXT_CSQC)
2021 static void VM_CL_getstats (prvm_prog_t *prog)
2022 {
2023         int i;
2024         char t[17];
2025         VM_SAFEPARMCOUNT(1, VM_CL_getstats);
2026         i = (int)PRVM_G_FLOAT(OFS_PARM0);
2027         if(i < 0 || i > MAX_CL_STATS-4)
2028         {
2029                 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2030                 VM_Warning(prog, "VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
2031                 return;
2032         }
2033         strlcpy(t, (char*)&cl.stats[i], sizeof(t));
2034         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
2035 }
2036
2037 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2038 static void VM_CL_setmodelindex (prvm_prog_t *prog)
2039 {
2040         int                             i;
2041         prvm_edict_t    *t;
2042         struct model_s  *model;
2043
2044         VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
2045
2046         t = PRVM_G_EDICT(OFS_PARM0);
2047
2048         i = (int)PRVM_G_FLOAT(OFS_PARM1);
2049
2050         PRVM_clientedictstring(t, model) = 0;
2051         PRVM_clientedictfloat(t, modelindex) = 0;
2052
2053         if (!i)
2054                 return;
2055
2056         model = CL_GetModelByIndex(i);
2057         if (!model)
2058         {
2059                 VM_Warning(prog, "VM_CL_setmodelindex: null model\n");
2060                 return;
2061         }
2062         PRVM_clientedictstring(t, model) = PRVM_SetEngineString(prog, model->name);
2063         PRVM_clientedictfloat(t, modelindex) = i;
2064
2065         // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
2066         if (model)
2067         {
2068                 SetMinMaxSize (prog, t, model->normalmins, model->normalmaxs);
2069         }
2070         else
2071                 SetMinMaxSize (prog, t, vec3_origin, vec3_origin);
2072 }
2073
2074 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2075 static void VM_CL_modelnameforindex (prvm_prog_t *prog)
2076 {
2077         model_t *model;
2078
2079         VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
2080
2081         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2082         model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
2083         PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(prog, model->name) : 0;
2084 }
2085
2086 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2087 static void VM_CL_particleeffectnum (prvm_prog_t *prog)
2088 {
2089         int                     i;
2090         VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
2091         i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
2092         if (i == 0)
2093                 i = -1;
2094         PRVM_G_FLOAT(OFS_RETURN) = i;
2095 }
2096
2097 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
2098 static void VM_CL_trailparticles (prvm_prog_t *prog)
2099 {
2100         int                             i;
2101         vec3_t                  start, end, velocity;
2102         prvm_edict_t    *t;
2103         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
2104
2105         t = PRVM_G_EDICT(OFS_PARM0);
2106         i               = (int)PRVM_G_FLOAT(OFS_PARM1);
2107         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2108         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2109         VectorCopy(PRVM_clientedictvector(t, velocity), velocity);
2110
2111         if (i < 0)
2112                 return;
2113         CL_ParticleTrail(i, 1, start, end, velocity, velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0, true, true, NULL, NULL, 1);
2114 }
2115
2116 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
2117 static void VM_CL_pointparticles (prvm_prog_t *prog)
2118 {
2119         int                     i;
2120         float n;
2121         vec3_t f, v;
2122         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
2123         i = (int)PRVM_G_FLOAT(OFS_PARM0);
2124         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f);
2125         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), v);
2126         n = PRVM_G_FLOAT(OFS_PARM3);
2127         if (i < 0)
2128                 return;
2129         CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
2130 }
2131
2132 //#502 void(float effectnum, entity own, vector origin_from, vector origin_to, vector dir_from, vector dir_to, float count, float extflags) boxparticles (DP_CSQC_BOXPARTICLES)
2133 static void VM_CL_boxparticles (prvm_prog_t *prog)
2134 {
2135         int effectnum;
2136         // prvm_edict_t *own;
2137         vec3_t origin_from, origin_to, dir_from, dir_to;
2138         float count;
2139         int flags;
2140         qbool istrail;
2141         float tintmins[4], tintmaxs[4], fade;
2142         VM_SAFEPARMCOUNTRANGE(7, 8, VM_CL_boxparticles);
2143
2144         effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2145         if (effectnum < 0)
2146                 return;
2147         // own = PRVM_G_EDICT(OFS_PARM1); // TODO find use for this
2148         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin_from);
2149         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin_to  );
2150         VectorCopy(PRVM_G_VECTOR(OFS_PARM4), dir_from   );
2151         VectorCopy(PRVM_G_VECTOR(OFS_PARM5), dir_to     );
2152         count = PRVM_G_FLOAT(OFS_PARM6);
2153         if(prog->argc >= 8)
2154                 flags = PRVM_G_FLOAT(OFS_PARM7);
2155         else
2156                 flags = 0;
2157
2158         Vector4Set(tintmins, 1, 1, 1, 1);
2159         Vector4Set(tintmaxs, 1, 1, 1, 1);
2160         fade = 1;
2161         istrail = false;
2162
2163         if(flags & 1) // read alpha
2164         {
2165                 tintmins[3] = PRVM_clientglobalfloat(particles_alphamin);
2166                 tintmaxs[3] = PRVM_clientglobalfloat(particles_alphamax);
2167         }
2168         if(flags & 2) // read color
2169         {
2170                 VectorCopy(PRVM_clientglobalvector(particles_colormin), tintmins);
2171                 VectorCopy(PRVM_clientglobalvector(particles_colormax), tintmaxs);
2172         }
2173         if(flags & 4) // read fade
2174         {
2175                 fade = PRVM_clientglobalfloat(particles_fade);
2176         }
2177         if(flags & 128) // draw as trail
2178         {
2179                 istrail = true;
2180         }
2181
2182         if (istrail)
2183                 CL_ParticleTrail(effectnum, count, origin_from, origin_to, dir_from, dir_to, NULL, 0, true, true, tintmins, tintmaxs, fade);
2184         else
2185                 CL_ParticleBox(effectnum, count, origin_from, origin_to, dir_from, dir_to, NULL, 0, true, true, tintmins, tintmaxs, fade);
2186 }
2187
2188 //#531 void(float pause) setpause
2189 static void VM_CL_setpause(prvm_prog_t *prog)
2190 {
2191         VM_SAFEPARMCOUNT(1, VM_CL_setpause);
2192         if(cl.islocalgame)
2193         {
2194                 if ((int)PRVM_G_FLOAT(OFS_PARM0) != 0)
2195                         host.paused = true;
2196                 else
2197                         host.paused = false;
2198         }
2199 }
2200
2201 //#343 void(float usecursor) setcursormode (DP_CSQC)
2202 static void VM_CL_setcursormode (prvm_prog_t *prog)
2203 {
2204         VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
2205         cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0) != 0;
2206         cl_ignoremousemoves = 2;
2207 }
2208
2209 //#344 vector() getmousepos (DP_CSQC)
2210 static void VM_CL_getmousepos(prvm_prog_t *prog)
2211 {
2212         VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
2213
2214         if (key_consoleactive || key_dest != key_game)
2215                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0);
2216         else if (cl.csqc_wantsmousemove)
2217                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
2218         else
2219                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
2220 }
2221
2222 //#345 float(float framenum) getinputstate (EXT_CSQC)
2223 static void VM_CL_getinputstate (prvm_prog_t *prog)
2224 {
2225         unsigned int i, frame;
2226         VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
2227         frame = (unsigned int)PRVM_G_FLOAT(OFS_PARM0);
2228         PRVM_G_FLOAT(OFS_RETURN) = false;
2229         for (i = 0;i < CL_MAX_USERCMDS;i++)
2230         {
2231                 if (cl.movecmd[i].sequence == frame)
2232                 {
2233                         VectorCopy(cl.movecmd[i].viewangles, PRVM_clientglobalvector(input_angles));
2234                         PRVM_clientglobalfloat(input_buttons) = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?)
2235                         PRVM_clientglobalvector(input_movevalues)[0] = cl.movecmd[i].forwardmove;
2236                         PRVM_clientglobalvector(input_movevalues)[1] = cl.movecmd[i].sidemove;
2237                         PRVM_clientglobalvector(input_movevalues)[2] = cl.movecmd[i].upmove;
2238                         PRVM_clientglobalfloat(input_timelength) = cl.movecmd[i].frametime;
2239                         // this probably shouldn't be here
2240                         if(cl.movecmd[i].crouch)
2241                         {
2242                                 VectorCopy(cl.playercrouchmins, PRVM_clientglobalvector(pmove_mins));
2243                                 VectorCopy(cl.playercrouchmaxs, PRVM_clientglobalvector(pmove_maxs));
2244                         }
2245                         else
2246                         {
2247                                 VectorCopy(cl.playerstandmins, PRVM_clientglobalvector(pmove_mins));
2248                                 VectorCopy(cl.playerstandmaxs, PRVM_clientglobalvector(pmove_maxs));
2249                         }
2250                         PRVM_G_FLOAT(OFS_RETURN) = true;
2251                 }
2252         }
2253 }
2254
2255 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
2256 static void VM_CL_setsensitivityscale (prvm_prog_t *prog)
2257 {
2258         VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
2259         cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
2260 }
2261
2262 //#347 void() runstandardplayerphysics (EXT_CSQC)
2263 #define PMF_JUMP_HELD 1 // matches FTEQW
2264 #define PMF_LADDER 2 // not used by DP, FTEQW sets this in runplayerphysics but does not read it
2265 #define PMF_DUCKED 4 // FIXME FTEQW doesn't have this for Q1 like movement because Q1 cannot crouch
2266 #define PMF_ONGROUND 8 // FIXME FTEQW doesn't have this for Q1 like movement and expects CSQC code to do its own trace, this is stupid CPU waste
2267 static void VM_CL_runplayerphysics (prvm_prog_t *prog)
2268 {
2269         cl_clientmovement_state_t s;
2270         prvm_edict_t *ent;
2271
2272         memset(&s, 0, sizeof(s));
2273
2274         VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_runplayerphysics);
2275
2276         ent = (prog->argc == 1 ? PRVM_G_EDICT(OFS_PARM0) : prog->edicts);
2277         if(ent == prog->edicts)
2278         {
2279                 // deprecated use
2280                 s.self = NULL;
2281                 VectorCopy(PRVM_clientglobalvector(pmove_org), s.origin);
2282                 VectorCopy(PRVM_clientglobalvector(pmove_vel), s.velocity);
2283                 VectorCopy(PRVM_clientglobalvector(pmove_mins), s.mins);
2284                 VectorCopy(PRVM_clientglobalvector(pmove_maxs), s.maxs);
2285                 s.crouched = 0;
2286                 s.waterjumptime = PRVM_clientglobalfloat(pmove_waterjumptime);
2287                 s.cmd.canjump = (int)PRVM_clientglobalfloat(pmove_jump_held) == 0;
2288         }
2289         else
2290         {
2291                 // new use
2292                 s.self = ent;
2293                 VectorCopy(PRVM_clientedictvector(ent, origin), s.origin);
2294                 VectorCopy(PRVM_clientedictvector(ent, velocity), s.velocity);
2295                 VectorCopy(PRVM_clientedictvector(ent, mins), s.mins);
2296                 VectorCopy(PRVM_clientedictvector(ent, maxs), s.maxs);
2297                 s.crouched = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_DUCKED) != 0;
2298                 s.waterjumptime = 0; // FIXME where do we get this from? FTEQW lacks support for this too
2299                 s.cmd.canjump = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_JUMP_HELD) == 0;
2300         }
2301
2302         VectorCopy(PRVM_clientglobalvector(input_angles), s.cmd.viewangles);
2303         s.cmd.forwardmove = PRVM_clientglobalvector(input_movevalues)[0];
2304         s.cmd.sidemove = PRVM_clientglobalvector(input_movevalues)[1];
2305         s.cmd.upmove = PRVM_clientglobalvector(input_movevalues)[2];
2306         s.cmd.buttons = PRVM_clientglobalfloat(input_buttons);
2307         s.cmd.frametime = PRVM_clientglobalfloat(input_timelength);
2308         s.cmd.jump = (s.cmd.buttons & 2) != 0;
2309         s.cmd.crouch = (s.cmd.buttons & 16) != 0;
2310
2311         CL_ClientMovement_PlayerMove_Frame(&s);
2312
2313         if(ent == prog->edicts)
2314         {
2315                 // deprecated use
2316                 VectorCopy(s.origin, PRVM_clientglobalvector(pmove_org));
2317                 VectorCopy(s.velocity, PRVM_clientglobalvector(pmove_vel));
2318                 PRVM_clientglobalfloat(pmove_jump_held) = !s.cmd.canjump;
2319                 PRVM_clientglobalfloat(pmove_waterjumptime) = s.waterjumptime;
2320         }
2321         else
2322         {
2323                 // new use
2324                 VectorCopy(s.origin, PRVM_clientedictvector(ent, origin));
2325                 VectorCopy(s.velocity, PRVM_clientedictvector(ent, velocity));
2326                 PRVM_clientedictfloat(ent, pmove_flags) =
2327                         (s.crouched ? PMF_DUCKED : 0) |
2328                         (s.cmd.canjump ? 0 : PMF_JUMP_HELD) |
2329                         (s.onground ? PMF_ONGROUND : 0);
2330         }
2331 }
2332
2333 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
2334 static void VM_CL_getplayerkey (prvm_prog_t *prog)
2335 {
2336         int                     i;
2337         char            t[128];
2338         const char      *c;
2339
2340         VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
2341
2342         i = (int)PRVM_G_FLOAT(OFS_PARM0);
2343         c = PRVM_G_STRING(OFS_PARM1);
2344         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2345         Sbar_SortFrags();
2346
2347         if (i < 0)
2348                 i = Sbar_GetSortedPlayerIndex(-1-i);
2349         if(i < 0 || i >= cl.maxclients)
2350                 return;
2351
2352         t[0] = 0;
2353
2354         if(!strcasecmp(c, "name"))
2355                 strlcpy(t, cl.scores[i].name, sizeof(t));
2356         else
2357                 if(!strcasecmp(c, "frags"))
2358                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].frags);
2359         else
2360                 if(!strcasecmp(c, "ping"))
2361                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_ping);
2362         else
2363                 if(!strcasecmp(c, "pl"))
2364                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_packetloss);
2365         else
2366                 if(!strcasecmp(c, "movementloss"))
2367                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_movementloss);
2368         else
2369                 if(!strcasecmp(c, "entertime"))
2370                         dpsnprintf(t, sizeof(t), "%f", cl.scores[i].qw_entertime);
2371         else
2372                 if(!strcasecmp(c, "colors"))
2373                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors);
2374         else
2375                 if(!strcasecmp(c, "topcolor"))
2376                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors & 0xf0);
2377         else
2378                 if(!strcasecmp(c, "bottomcolor"))
2379                         dpsnprintf(t, sizeof(t), "%i", (cl.scores[i].colors &15)<<4);
2380         else
2381                 if(!strcasecmp(c, "viewentity"))
2382                         dpsnprintf(t, sizeof(t), "%i", i+1);
2383         if(!t[0])
2384                 return;
2385         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
2386 }
2387
2388 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
2389 static void VM_CL_setlistener (prvm_prog_t *prog)
2390 {
2391         vec3_t origin, forward, left, up;
2392         VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
2393         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), origin);
2394         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), forward);
2395         VectorNegate(PRVM_G_VECTOR(OFS_PARM2), left);
2396         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), up);
2397         Matrix4x4_FromVectors(&cl.csqc_listenermatrix, forward, left, up, origin);
2398         cl.csqc_usecsqclistener = true; //use csqc listener at this frame
2399 }
2400
2401 //#352 void(string cmdname) registercommand (EXT_CSQC)
2402 static void VM_CL_registercmd (prvm_prog_t *prog)
2403 {
2404         VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
2405         if(!Cmd_Exists(cmd_local, PRVM_G_STRING(OFS_PARM0)))
2406                 Cmd_AddCommand(CF_CLIENT, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
2407 }
2408
2409 //#360 float() readbyte (EXT_CSQC)
2410 static void VM_CL_ReadByte (prvm_prog_t *prog)
2411 {
2412         VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
2413         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte(&cl_message);
2414 }
2415
2416 //#361 float() readchar (EXT_CSQC)
2417 static void VM_CL_ReadChar (prvm_prog_t *prog)
2418 {
2419         VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
2420         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar(&cl_message);
2421 }
2422
2423 //#362 float() readshort (EXT_CSQC)
2424 static void VM_CL_ReadShort (prvm_prog_t *prog)
2425 {
2426         VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
2427         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort(&cl_message);
2428 }
2429
2430 //#363 float() readlong (EXT_CSQC)
2431 static void VM_CL_ReadLong (prvm_prog_t *prog)
2432 {
2433         VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
2434         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong(&cl_message);
2435 }
2436
2437 //#364 float() readcoord (EXT_CSQC)
2438 static void VM_CL_ReadCoord (prvm_prog_t *prog)
2439 {
2440         VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
2441         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(&cl_message, cls.protocol);
2442 }
2443
2444 //#365 float() readangle (EXT_CSQC)
2445 static void VM_CL_ReadAngle (prvm_prog_t *prog)
2446 {
2447         VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
2448         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(&cl_message, cls.protocol);
2449 }
2450
2451 //#366 string() readstring (EXT_CSQC)
2452 static void VM_CL_ReadString (prvm_prog_t *prog)
2453 {
2454         VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
2455         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
2456 }
2457
2458 //#367 float() readfloat (EXT_CSQC)
2459 static void VM_CL_ReadFloat (prvm_prog_t *prog)
2460 {
2461         VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
2462         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat(&cl_message);
2463 }
2464
2465 //#501 string() readpicture (DP_CSQC_READWRITEPICTURE)
2466 extern cvar_t cl_readpicture_force;
2467 static void VM_CL_ReadPicture (prvm_prog_t *prog)
2468 {
2469         const char *name;
2470         unsigned char *data;
2471         unsigned char *buf;
2472         unsigned short size;
2473         int i;
2474         cachepic_t *pic;
2475
2476         VM_SAFEPARMCOUNT(0, VM_CL_ReadPicture);
2477
2478         name = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
2479         size = (unsigned short) MSG_ReadShort(&cl_message);
2480
2481         // check if a texture of that name exists
2482         // if yes, it is used and the data is discarded
2483         // if not, the (low quality) data is used to build a new texture, whose name will get returned
2484
2485         pic = Draw_CachePic_Flags(name, CACHEPICFLAG_NOTPERSISTENT | CACHEPICFLAG_FAILONMISSING);
2486
2487         if(size)
2488         {
2489                 if (Draw_IsPicLoaded(pic) && !cl_readpicture_force.integer)
2490                 {
2491                         // texture found and loaded
2492                         // skip over the jpeg as we don't need it
2493                         for(i = 0; i < size; ++i)
2494                                 (void) MSG_ReadByte(&cl_message);
2495                 }
2496                 else
2497                 {
2498                         // texture not found
2499                         // use the attached jpeg as texture
2500                         buf = (unsigned char *) Mem_Alloc(tempmempool, size);
2501                         MSG_ReadBytes(&cl_message, size, buf);
2502                         data = JPEG_LoadImage_BGRA(buf, size, NULL);
2503                         Mem_Free(buf);
2504                         Draw_NewPic(name, image_width, image_height, data, TEXTYPE_BGRA, TEXF_CLAMP);
2505                         Mem_Free(data);
2506                 }
2507         }
2508
2509         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, name);
2510 }
2511
2512 //////////////////////////////////////////////////////////
2513
2514 static void VM_CL_makestatic (prvm_prog_t *prog)
2515 {
2516         prvm_edict_t *ent;
2517
2518         VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
2519
2520         ent = PRVM_G_EDICT(OFS_PARM0);
2521         if (ent == prog->edicts)
2522         {
2523                 VM_Warning(prog, "makestatic: can not modify world entity\n");
2524                 return;
2525         }
2526         if (ent->priv.server->free)
2527         {
2528                 VM_Warning(prog, "makestatic: can not modify free entity\n");
2529                 return;
2530         }
2531
2532         if (cl.num_static_entities < cl.max_static_entities)
2533         {
2534                 int renderflags;
2535                 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
2536
2537                 // copy it to the current state
2538                 memset(staticent, 0, sizeof(*staticent));
2539                 staticent->render.model = CL_GetModelByIndex((int)PRVM_clientedictfloat(ent, modelindex));
2540                 staticent->render.framegroupblend[0].frame = (int)PRVM_clientedictfloat(ent, frame);
2541                 staticent->render.framegroupblend[0].lerp = 1;
2542                 // make torchs play out of sync
2543                 staticent->render.framegroupblend[0].start = lhrandom(-10, -1);
2544                 staticent->render.skinnum = (int)PRVM_clientedictfloat(ent, skin);
2545                 staticent->render.effects = (int)PRVM_clientedictfloat(ent, effects);
2546                 staticent->render.alpha = PRVM_clientedictfloat(ent, alpha);
2547                 staticent->render.scale = PRVM_clientedictfloat(ent, scale);
2548                 VectorCopy(PRVM_clientedictvector(ent, colormod), staticent->render.colormod);
2549                 VectorCopy(PRVM_clientedictvector(ent, glowmod), staticent->render.glowmod);
2550
2551                 // sanitize values
2552                 if (!staticent->render.alpha)
2553                         staticent->render.alpha = 1.0f;
2554                 if (!staticent->render.scale)
2555                         staticent->render.scale = 1.0f;
2556                 if (!VectorLength2(staticent->render.colormod))
2557                         VectorSet(staticent->render.colormod, 1, 1, 1);
2558                 if (!VectorLength2(staticent->render.glowmod))
2559                         VectorSet(staticent->render.glowmod, 1, 1, 1);
2560
2561                 renderflags = (int)PRVM_clientedictfloat(ent, renderflags);
2562                 if (renderflags & RF_USEAXIS)
2563                 {
2564                         vec3_t forward, left, up, origin;
2565                         VectorCopy(PRVM_clientglobalvector(v_forward), forward);
2566                         VectorNegate(PRVM_clientglobalvector(v_right), left);
2567                         VectorCopy(PRVM_clientglobalvector(v_up), up);
2568                         VectorCopy(PRVM_clientedictvector(ent, origin), origin);
2569                         Matrix4x4_FromVectors(&staticent->render.matrix, forward, left, up, origin);
2570                         Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
2571                 }
2572                 else
2573                         Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, PRVM_clientedictvector(ent, origin)[0], PRVM_clientedictvector(ent, origin)[1], PRVM_clientedictvector(ent, origin)[2], PRVM_clientedictvector(ent, angles)[0], PRVM_clientedictvector(ent, angles)[1], PRVM_clientedictvector(ent, angles)[2], staticent->render.scale);
2574
2575                 // either fullbright or lit
2576                 if(!r_fullbright.integer)
2577                 {
2578                         if (!(staticent->render.effects & EF_FULLBRIGHT))
2579                                 staticent->render.flags |= RENDER_LIGHT;
2580                 }
2581                 // turn off shadows from transparent objects
2582                 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
2583                         staticent->render.flags |= RENDER_SHADOW;
2584                 if (staticent->render.effects & EF_NODEPTHTEST)
2585                         staticent->render.flags |= RENDER_NODEPTHTEST;
2586                 if (staticent->render.effects & EF_ADDITIVE)
2587                         staticent->render.flags |= RENDER_ADDITIVE;
2588                 if (staticent->render.effects & EF_DOUBLESIDED)
2589                         staticent->render.flags |= RENDER_DOUBLESIDED;
2590
2591                 staticent->render.allowdecals = true;
2592                 CL_UpdateRenderEntity(&staticent->render);
2593         }
2594         else
2595                 Con_Printf("Too many static entities");
2596
2597 // throw the entity away now
2598         PRVM_ED_Free(prog, ent);
2599 }
2600
2601 //=================================================================//
2602
2603 /*
2604 =================
2605 VM_CL_copyentity
2606
2607 copies data from one entity to another
2608
2609 copyentity(src, dst)
2610 =================
2611 */
2612 static void VM_CL_copyentity (prvm_prog_t *prog)
2613 {
2614         prvm_edict_t *in, *out;
2615         VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
2616         in = PRVM_G_EDICT(OFS_PARM0);
2617         if (in == prog->edicts)
2618         {
2619                 VM_Warning(prog, "copyentity: can not read world entity\n");
2620                 return;
2621         }
2622         if (in->priv.server->free)
2623         {
2624                 VM_Warning(prog, "copyentity: can not read free entity\n");
2625                 return;
2626         }
2627         out = PRVM_G_EDICT(OFS_PARM1);
2628         if (out == prog->edicts)
2629         {
2630                 VM_Warning(prog, "copyentity: can not modify world entity\n");
2631                 return;
2632         }
2633         if (out->priv.server->free)
2634         {
2635                 VM_Warning(prog, "copyentity: can not modify free entity\n");
2636                 return;
2637         }
2638         memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
2639
2640         if (VectorCompare(PRVM_clientedictvector(out, absmin), PRVM_clientedictvector(out, absmax)))
2641                 return;
2642         CL_LinkEdict(out);
2643 }
2644
2645 //=================================================================//
2646
2647 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2648 static void VM_CL_effect (prvm_prog_t *prog)
2649 {
2650         model_t *model;
2651         vec3_t org;
2652         VM_SAFEPARMCOUNT(5, VM_CL_effect);
2653         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
2654
2655         model = Mod_FindName(PRVM_G_STRING(OFS_PARM1), NULL);
2656         if(model->loaded)
2657                 CL_Effect(org, model, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
2658         else
2659                 Con_Printf(CON_ERROR "VM_CL_effect: Could not load model '%s'\n", PRVM_G_STRING(OFS_PARM1));
2660 }
2661
2662 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2663 static void VM_CL_te_blood (prvm_prog_t *prog)
2664 {
2665         vec3_t pos, vel, pos2;
2666         VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
2667         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2668                 return;
2669         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2670         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel);
2671         CL_FindNonSolidLocation(pos, pos2, 4);
2672         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0);
2673 }
2674
2675 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2676 static void VM_CL_te_bloodshower (prvm_prog_t *prog)
2677 {
2678         vec_t speed;
2679         vec3_t mincorner, maxcorner, vel1, vel2;
2680         VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
2681         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2682                 return;
2683         speed = PRVM_G_FLOAT(OFS_PARM2);
2684         vel1[0] = -speed;
2685         vel1[1] = -speed;
2686         vel1[2] = -speed;
2687         vel2[0] = speed;
2688         vel2[1] = speed;
2689         vel2[2] = speed;
2690         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2691         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2692         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), mincorner, maxcorner, vel1, vel2, NULL, 0);
2693 }
2694
2695 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2696 static void VM_CL_te_explosionrgb (prvm_prog_t *prog)
2697 {
2698         vec3_t          pos;
2699         vec3_t          pos2;
2700         matrix4x4_t     tempmatrix;
2701         VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
2702         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2703         CL_FindNonSolidLocation(pos, pos2, 10);
2704         CL_ParticleExplosion(pos2);
2705         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
2706         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, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
2707 }
2708
2709 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2710 static void VM_CL_te_particlecube (prvm_prog_t *prog)
2711 {
2712         vec3_t mincorner, maxcorner, vel;
2713         VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
2714         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2715         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2716         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2717         CL_ParticleCube(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), PRVM_G_FLOAT(OFS_PARM5), PRVM_G_FLOAT(OFS_PARM6));
2718 }
2719
2720 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2721 static void VM_CL_te_particlerain (prvm_prog_t *prog)
2722 {
2723         vec3_t mincorner, maxcorner, vel;
2724         VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
2725         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2726         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2727         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2728         CL_ParticleRain(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 0);
2729 }
2730
2731 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2732 static void VM_CL_te_particlesnow (prvm_prog_t *prog)
2733 {
2734         vec3_t mincorner, maxcorner, vel;
2735         VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
2736         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2737         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2738         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2739         CL_ParticleRain(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 1);
2740 }
2741
2742 // #411 void(vector org, vector vel, float howmany) te_spark
2743 static void VM_CL_te_spark (prvm_prog_t *prog)
2744 {
2745         vec3_t pos, pos2, vel;
2746         VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
2747
2748         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2749         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel);
2750         CL_FindNonSolidLocation(pos, pos2, 4);
2751         CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0);
2752 }
2753
2754 extern cvar_t cl_sound_ric_gunshot;
2755 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2756 static void VM_CL_te_gunshotquad (prvm_prog_t *prog)
2757 {
2758         vec3_t          pos, pos2;
2759         int                     rnd;
2760         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
2761
2762         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2763         CL_FindNonSolidLocation(pos, pos2, 4);
2764         CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2765         if(cl_sound_ric_gunshot.integer >= 2)
2766         {
2767                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2768                 else
2769                 {
2770                         rnd = rand() & 3;
2771                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2772                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2773                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2774                 }
2775         }
2776 }
2777
2778 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2779 static void VM_CL_te_spikequad (prvm_prog_t *prog)
2780 {
2781         vec3_t          pos, pos2;
2782         int                     rnd;
2783         VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
2784
2785         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2786         CL_FindNonSolidLocation(pos, pos2, 4);
2787         CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2788         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2789         else
2790         {
2791                 rnd = rand() & 3;
2792                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2793                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2794                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2795         }
2796 }
2797
2798 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2799 static void VM_CL_te_superspikequad (prvm_prog_t *prog)
2800 {
2801         vec3_t          pos, pos2;
2802         int                     rnd;
2803         VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
2804
2805         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2806         CL_FindNonSolidLocation(pos, pos2, 4);
2807         CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2808         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
2809         else
2810         {
2811                 rnd = rand() & 3;
2812                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2813                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2814                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2815         }
2816 }
2817
2818 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2819 static void VM_CL_te_explosionquad (prvm_prog_t *prog)
2820 {
2821         vec3_t          pos, pos2;
2822         VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
2823
2824         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2825         CL_FindNonSolidLocation(pos, pos2, 10);
2826         CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2827         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
2828 }
2829
2830 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2831 static void VM_CL_te_smallflash (prvm_prog_t *prog)
2832 {
2833         vec3_t          pos, pos2;
2834         VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
2835
2836         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2837         CL_FindNonSolidLocation(pos, pos2, 10);
2838         CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2839 }
2840
2841 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2842 static void VM_CL_te_customflash (prvm_prog_t *prog)
2843 {
2844         vec3_t          pos, pos2;
2845         matrix4x4_t     tempmatrix;
2846         VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
2847
2848         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2849         CL_FindNonSolidLocation(pos, pos2, 4);
2850         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
2851         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), NULL, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
2852 }
2853
2854 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2855 static void VM_CL_te_gunshot (prvm_prog_t *prog)
2856 {
2857         vec3_t          pos, pos2;
2858         int                     rnd;
2859         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
2860
2861         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2862         CL_FindNonSolidLocation(pos, pos2, 4);
2863         CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2864         if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
2865         {
2866                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2867                 else
2868                 {
2869                         rnd = rand() & 3;
2870                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2871                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2872                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2873                 }
2874         }
2875 }
2876
2877 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2878 static void VM_CL_te_spike (prvm_prog_t *prog)
2879 {
2880         vec3_t          pos, pos2;
2881         int                     rnd;
2882         VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
2883
2884         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2885         CL_FindNonSolidLocation(pos, pos2, 4);
2886         CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2887         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2888         else
2889         {
2890                 rnd = rand() & 3;
2891                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2892                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2893                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2894         }
2895 }
2896
2897 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2898 static void VM_CL_te_superspike (prvm_prog_t *prog)
2899 {
2900         vec3_t          pos, pos2;
2901         int                     rnd;
2902         VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
2903
2904         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2905         CL_FindNonSolidLocation(pos, pos2, 4);
2906         CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2907         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2908         else
2909         {
2910                 rnd = rand() & 3;
2911                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2912                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2913                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2914         }
2915 }
2916
2917 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2918 static void VM_CL_te_explosion (prvm_prog_t *prog)
2919 {
2920         vec3_t          pos, pos2;
2921         VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
2922
2923         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2924         CL_FindNonSolidLocation(pos, pos2, 10);
2925         CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2926         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
2927 }
2928
2929 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2930 static void VM_CL_te_tarexplosion (prvm_prog_t *prog)
2931 {
2932         vec3_t          pos, pos2;
2933         VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
2934
2935         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2936         CL_FindNonSolidLocation(pos, pos2, 10);
2937         CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2938         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
2939 }
2940
2941 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2942 static void VM_CL_te_wizspike (prvm_prog_t *prog)
2943 {
2944         vec3_t          pos, pos2;
2945         VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
2946
2947         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2948         CL_FindNonSolidLocation(pos, pos2, 4);
2949         CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2950         S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
2951 }
2952
2953 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2954 static void VM_CL_te_knightspike (prvm_prog_t *prog)
2955 {
2956         vec3_t          pos, pos2;
2957         VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
2958
2959         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2960         CL_FindNonSolidLocation(pos, pos2, 4);
2961         CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2962         S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
2963 }
2964
2965 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2966 static void VM_CL_te_lavasplash (prvm_prog_t *prog)
2967 {
2968         vec3_t          pos;
2969         VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
2970         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2971         CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
2972 }
2973
2974 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2975 static void VM_CL_te_teleport (prvm_prog_t *prog)
2976 {
2977         vec3_t          pos;
2978         VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
2979         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2980         CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
2981 }
2982
2983 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2984 static void VM_CL_te_explosion2 (prvm_prog_t *prog)
2985 {
2986         vec3_t          pos, pos2, color;
2987         matrix4x4_t     tempmatrix;
2988         int                     colorStart, colorLength;
2989         unsigned char           *tempcolor;
2990         VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
2991
2992         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2993         colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
2994         colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
2995         CL_FindNonSolidLocation(pos, pos2, 10);
2996         CL_ParticleExplosion2(pos2, colorStart, colorLength);
2997         tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
2998         color[0] = tempcolor[0] * (2.0f / 255.0f);
2999         color[1] = tempcolor[1] * (2.0f / 255.0f);
3000         color[2] = tempcolor[2] * (2.0f / 255.0f);
3001         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
3002         CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
3003         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
3004 }
3005
3006
3007 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3008 static void VM_CL_te_lightning1 (prvm_prog_t *prog)
3009 {
3010         vec3_t          start, end;
3011         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
3012         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3013         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3014         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt, true);
3015 }
3016
3017 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3018 static void VM_CL_te_lightning2 (prvm_prog_t *prog)
3019 {
3020         vec3_t          start, end;
3021         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
3022         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3023         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3024         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt2, true);
3025 }
3026
3027 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3028 static void VM_CL_te_lightning3 (prvm_prog_t *prog)
3029 {
3030         vec3_t          start, end;
3031         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
3032         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3033         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3034         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt3, false);
3035 }
3036
3037 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3038 static void VM_CL_te_beam (prvm_prog_t *prog)
3039 {
3040         vec3_t          start, end;
3041         VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
3042         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3043         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3044         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_beam, false);
3045 }
3046
3047 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3048 static void VM_CL_te_plasmaburn (prvm_prog_t *prog)
3049 {
3050         vec3_t          pos, pos2;
3051         VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
3052
3053         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
3054         CL_FindNonSolidLocation(pos, pos2, 4);
3055         CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
3056 }
3057
3058 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
3059 static void VM_CL_te_flamejet (prvm_prog_t *prog)
3060 {
3061         vec3_t          pos, pos2, vel;
3062         VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
3063         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
3064                 return;
3065         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
3066         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel);
3067         CL_FindNonSolidLocation(pos, pos2, 4);
3068         CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0);
3069 }
3070
3071
3072 // #443 void(entity e, entity tagentity, string tagname) setattachment
3073 static void VM_CL_setattachment (prvm_prog_t *prog)
3074 {
3075         prvm_edict_t *e;
3076         prvm_edict_t *tagentity;
3077         const char *tagname;
3078         int modelindex;
3079         int tagindex;
3080         model_t *model;
3081         VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
3082
3083         e = PRVM_G_EDICT(OFS_PARM0);
3084         tagentity = PRVM_G_EDICT(OFS_PARM1);
3085         tagname = PRVM_G_STRING(OFS_PARM2);
3086
3087         if (e == prog->edicts)
3088         {
3089                 VM_Warning(prog, "setattachment: can not modify world entity\n");
3090                 return;
3091         }
3092         if (e->priv.server->free)
3093         {
3094                 VM_Warning(prog, "setattachment: can not modify free entity\n");
3095                 return;
3096         }
3097
3098         if (tagentity == NULL)
3099                 tagentity = prog->edicts;
3100
3101         tagindex = 0;
3102         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
3103         {
3104                 modelindex = (int)PRVM_clientedictfloat(tagentity, modelindex);
3105                 model = CL_GetModelByIndex(modelindex);
3106                 if (model)
3107                 {
3108                         tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(tagentity, skin), tagname);
3109                         if (tagindex == 0)
3110                                 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);
3111                 }
3112                 else
3113                         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));
3114         }
3115
3116         PRVM_clientedictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
3117         PRVM_clientedictfloat(e, tag_index) = tagindex;
3118 }
3119
3120 /////////////////////////////////////////
3121 // DP_MD3_TAGINFO extension coded by VorteX
3122
3123 static int CL_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
3124 {
3125         model_t *model = CL_GetModelFromEdict(e);
3126         if (model)
3127                 return Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(e, skin), tagname);
3128         else
3129                 return -1;
3130 }
3131
3132 static int CL_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
3133 {
3134         int r;
3135         model_t *model;
3136
3137         *tagname = NULL;
3138         *parentindex = 0;
3139         Matrix4x4_CreateIdentity(tag_localmatrix);
3140
3141         if (tagindex >= 0
3142          && (model = CL_GetModelFromEdict(e))
3143          && model->animscenes)
3144         {
3145                 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_clientedictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
3146
3147                 if(!r) // success?
3148                         *parentindex += 1;
3149
3150                 return r;
3151         }
3152
3153         return 1;
3154 }
3155
3156 int CL_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent)
3157 {
3158         model_t *model;
3159         if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
3160                 return -1;
3161         return 1;
3162 }
3163
3164 void CL_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix)
3165 {
3166         float scale;
3167         float pitchsign = 1;
3168
3169         scale = PRVM_clientedictfloat(ent, scale);
3170         if (!scale)
3171                 scale = 1.0f;
3172
3173         if(viewmatrix)
3174                 *out = r_refdef.view.matrix;
3175         else if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_USEAXIS)
3176         {
3177                 vec3_t forward;
3178                 vec3_t left;
3179                 vec3_t up;
3180                 vec3_t origin;
3181                 VectorScale(PRVM_clientglobalvector(v_forward), scale, forward);
3182                 VectorScale(PRVM_clientglobalvector(v_right), -scale, left);
3183                 VectorScale(PRVM_clientglobalvector(v_up), scale, up);
3184                 VectorCopy(PRVM_clientedictvector(ent, origin), origin);
3185                 Matrix4x4_FromVectors(out, forward, left, up, origin);
3186         }
3187         else
3188         {
3189                 pitchsign = CL_GetPitchSign(prog, ent);
3190                 Matrix4x4_CreateFromQuakeEntity(out, PRVM_clientedictvector(ent, origin)[0], PRVM_clientedictvector(ent, origin)[1], PRVM_clientedictvector(ent, origin)[2], pitchsign * PRVM_clientedictvector(ent, angles)[0], PRVM_clientedictvector(ent, angles)[1], PRVM_clientedictvector(ent, angles)[2], scale);
3191         }
3192 }
3193
3194 static int CL_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
3195 {
3196         model_t *model;
3197         if (tagindex >= 0
3198          && (model = CL_GetModelFromEdict(ent))
3199          && model->animscenes)
3200         {
3201                 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
3202                 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, cl.time);
3203                 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
3204                 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
3205         }
3206         *out = identitymatrix;
3207         return 0;
3208 }
3209
3210 // Warnings/errors code:
3211 // 0 - normal (everything all-right)
3212 // 1 - world entity
3213 // 2 - free entity
3214 // 3 - null or non-precached model
3215 // 4 - no tags with requested index
3216 // 5 - runaway loop at attachment chain
3217 extern cvar_t cl_bob;
3218 extern cvar_t cl_bobcycle;
3219 extern cvar_t cl_bobup;
3220 int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex, prvm_vec_t *returnshadingorigin)
3221 {
3222         int ret;
3223         int attachloop;
3224         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3225         model_t *model;
3226         vec3_t shadingorigin;
3227
3228         *out = identitymatrix; // warnings and errors return identical matrix
3229
3230         if (ent == prog->edicts)
3231                 return 1;
3232         if (ent->priv.server->free)
3233                 return 2;
3234
3235         model = CL_GetModelFromEdict(ent);
3236         if(!model)
3237                 return 3;
3238
3239         tagmatrix = identitymatrix;
3240         attachloop = 0;
3241         for(;;)
3242         {
3243                 if(attachloop >= 256)
3244                         return 5;
3245                 // apply transformation by child's tagindex on parent entity and then
3246                 // by parent entity itself
3247                 ret = CL_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
3248                 if(ret && attachloop == 0)
3249                         return ret;
3250                 CL_GetEntityMatrix(prog, ent, &entitymatrix, false);
3251                 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
3252                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3253                 // next iteration we process the parent entity
3254                 if (PRVM_clientedictedict(ent, tag_entity))
3255                 {
3256                         tagindex = (int)PRVM_clientedictfloat(ent, tag_index);
3257                         ent = PRVM_EDICT_NUM(PRVM_clientedictedict(ent, tag_entity));
3258                 }
3259                 else
3260                         break;
3261                 attachloop++;
3262         }
3263
3264         // RENDER_VIEWMODEL magic
3265         if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_VIEWMODEL)
3266         {
3267                 Matrix4x4_Copy(&tagmatrix, out);
3268
3269                 CL_GetEntityMatrix(prog, prog->edicts, &entitymatrix, true);
3270                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3271
3272                 /*
3273                 // Cl_bob, ported from rendering code
3274                 if (PRVM_clientedictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
3275                 {
3276                         double bob, cycle;
3277                         // LadyHavoc: this code is *weird*, but not replacable (I think it
3278                         // should be done in QC on the server, but oh well, quake is quake)
3279                         // LadyHavoc: figured out bobup: the time at which the sin is at 180
3280                         // degrees (which allows lengthening or squishing the peak or valley)
3281                         cycle = cl.time/cl_bobcycle.value;
3282                         cycle -= (int)cycle;
3283                         if (cycle < cl_bobup.value)
3284                                 cycle = sin(M_PI * cycle / cl_bobup.value);
3285                         else
3286                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3287                         // bob is proportional to velocity in the xy plane
3288                         // (don't count Z, or jumping messes it up)
3289                         bob = sqrt(PRVM_clientedictvector(ent, velocity)[0]*PRVM_clientedictvector(ent, velocity)[0] + PRVM_clientedictvector(ent, velocity)[1]*PRVM_clientedictvector(ent, velocity)[1])*cl_bob.value;
3290                         bob = bob*0.3 + bob*0.7*cycle;
3291                         Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
3292                 }
3293                 */
3294
3295                 // return the origin of the view
3296                 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, shadingorigin);
3297         }
3298         else
3299         {
3300                 // return the origin of the root entity in the chain
3301                 Matrix4x4_OriginFromMatrix(out, shadingorigin);
3302         }
3303         if (returnshadingorigin)
3304                 VectorCopy(shadingorigin, returnshadingorigin);
3305         return 0;
3306 }
3307
3308 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3309 static void VM_CL_gettagindex (prvm_prog_t *prog)
3310 {
3311         prvm_edict_t *ent;
3312         const char *tag_name;
3313         int tag_index;
3314
3315         VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
3316
3317         ent = PRVM_G_EDICT(OFS_PARM0);
3318         tag_name = PRVM_G_STRING(OFS_PARM1);
3319         if (ent == prog->edicts)
3320         {
3321                 VM_Warning(prog, "VM_CL_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
3322                 return;
3323         }
3324         if (ent->priv.server->free)
3325         {
3326                 VM_Warning(prog, "VM_CL_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
3327                 return;
3328         }
3329
3330         tag_index = 0;
3331         if (!CL_GetModelFromEdict(ent))
3332                 Con_DPrintf("VM_CL_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
3333         else
3334         {
3335                 tag_index = CL_GetTagIndex(prog, ent, tag_name);
3336                 if (tag_index == 0)
3337                         if(developer_extra.integer)
3338                                 Con_DPrintf("VM_CL_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
3339         }
3340         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
3341 }
3342
3343 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3344 static void VM_CL_gettaginfo (prvm_prog_t *prog)
3345 {
3346         prvm_edict_t *e;
3347         int tagindex;
3348         matrix4x4_t tag_matrix;
3349         matrix4x4_t tag_localmatrix;
3350         int parentindex;
3351         const char *tagname;
3352         int returncode;
3353         vec3_t forward, left, up, origin;
3354         const model_t *model;
3355
3356         VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
3357
3358         e = PRVM_G_EDICT(OFS_PARM0);
3359         tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
3360         returncode = CL_GetTagMatrix(prog, &tag_matrix, e, tagindex, NULL);
3361         Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
3362         VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3363         VectorScale(left, -1, PRVM_clientglobalvector(v_right));
3364         VectorCopy(up, PRVM_clientglobalvector(v_up));
3365         VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3366         model = CL_GetModelFromEdict(e);
3367         VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
3368         VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, cl.time);
3369         VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
3370         CL_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
3371         Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
3372
3373         PRVM_clientglobalfloat(gettaginfo_parent) = parentindex;
3374         PRVM_clientglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
3375         VectorCopy(forward, PRVM_clientglobalvector(gettaginfo_forward));
3376         VectorScale(left, -1, PRVM_clientglobalvector(gettaginfo_right));
3377         VectorCopy(up, PRVM_clientglobalvector(gettaginfo_up));
3378         VectorCopy(origin, PRVM_clientglobalvector(gettaginfo_offset));
3379
3380         switch(returncode)
3381         {
3382                 case 1:
3383                         VM_Warning(prog, "gettagindex: can't affect world entity\n");
3384                         break;
3385                 case 2:
3386                         VM_Warning(prog, "gettagindex: can't affect free entity\n");
3387                         break;
3388                 case 3:
3389                         Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
3390                         break;
3391                 case 4:
3392                         Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
3393                         break;
3394                 case 5:
3395                         Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
3396                         break;
3397         }
3398 }
3399
3400 //============================================================================
3401
3402 //====================
3403 // DP_CSQC_SPAWNPARTICLE
3404 // a QC hook to engine's CL_NewParticle
3405 //====================
3406
3407 // particle theme struct
3408 typedef struct vmparticletheme_s
3409 {
3410         unsigned short typeindex;
3411         qbool initialized;
3412         pblend_t blendmode;
3413         porientation_t orientation;
3414         int color1;
3415         int color2;
3416         int tex;
3417         float size;
3418         float sizeincrease;
3419         float alpha;
3420         float alphafade;
3421         float gravity;
3422         float bounce;
3423         float airfriction;
3424         float liquidfriction;
3425         float originjitter;
3426         float velocityjitter;
3427         qbool qualityreduction;
3428         float lifetime;
3429         float stretch;
3430         int staincolor1;
3431         int staincolor2;
3432         int staintex;
3433         float stainalpha;
3434         float stainsize;
3435         float delayspawn;
3436         float delaycollision;
3437         float angle;
3438         float spin;
3439 }vmparticletheme_t;
3440
3441 // particle spawner
3442 typedef struct vmparticlespawner_s
3443 {
3444         mempool_t                       *pool;
3445         qbool                   initialized;
3446         qbool                   verified;
3447         vmparticletheme_t       *themes;
3448         int                                     max_themes;
3449 }vmparticlespawner_t;
3450
3451 vmparticlespawner_t vmpartspawner;
3452
3453 // TODO: automatic max_themes grow
3454 static void VM_InitParticleSpawner (prvm_prog_t *prog, int maxthemes)
3455 {
3456         // bound max themes to not be an insane value
3457         if (maxthemes < 4)
3458                 maxthemes = 4;
3459         if (maxthemes > 2048)
3460                 maxthemes = 2048;
3461         // allocate and set up structure
3462         if (vmpartspawner.initialized) // reallocate
3463         {
3464                 Mem_FreePool(&vmpartspawner.pool);
3465                 memset(&vmpartspawner, 0, sizeof(vmparticlespawner_t));
3466         }
3467         vmpartspawner.pool = Mem_AllocPool("VMPARTICLESPAWNER", 0, NULL);
3468         vmpartspawner.themes = (vmparticletheme_t *)Mem_Alloc(vmpartspawner.pool, sizeof(vmparticletheme_t)*maxthemes);
3469         vmpartspawner.max_themes = maxthemes;
3470         vmpartspawner.initialized = true;
3471         vmpartspawner.verified = true;
3472 }
3473
3474 // reset particle theme to default values
3475 static void VM_ResetParticleTheme (vmparticletheme_t *theme)
3476 {
3477         theme->initialized = true;
3478         theme->typeindex = pt_static;
3479         theme->blendmode = PBLEND_ADD;
3480         theme->orientation = PARTICLE_BILLBOARD;
3481         theme->color1 = 0x808080;
3482         theme->color2 = 0xFFFFFF;
3483         theme->tex = 63;
3484         theme->size = 2;
3485         theme->sizeincrease = 0;
3486         theme->alpha = 256;
3487         theme->alphafade = 512;
3488         theme->gravity = 0.0f;
3489         theme->bounce = 0.0f;
3490         theme->airfriction = 1.0f;
3491         theme->liquidfriction = 4.0f;
3492         theme->originjitter = 0.0f;
3493         theme->velocityjitter = 0.0f;
3494         theme->qualityreduction = false;
3495         theme->lifetime = 4;
3496         theme->stretch = 1;
3497         theme->staincolor1 = -1;
3498         theme->staincolor2 = -1;
3499         theme->staintex = -1;
3500         theme->delayspawn = 0.0f;
3501         theme->delaycollision = 0.0f;
3502         theme->angle = 0.0f;
3503         theme->spin = 0.0f;
3504 }
3505
3506 // particle theme -> QC globals
3507 static void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme, prvm_prog_t *prog)
3508 {
3509         PRVM_clientglobalfloat(particle_type) = theme->typeindex;
3510         PRVM_clientglobalfloat(particle_blendmode) = theme->blendmode;
3511         PRVM_clientglobalfloat(particle_orientation) = theme->orientation;
3512         // VorteX: int only can store 0-255, not 0-256 which means 0 - 0,99609375...
3513         VectorSet(PRVM_clientglobalvector(particle_color1), (theme->color1 >> 16) & 0xFF, (theme->color1 >> 8) & 0xFF, (theme->color1 >> 0) & 0xFF);
3514         VectorSet(PRVM_clientglobalvector(particle_color2), (theme->color2 >> 16) & 0xFF, (theme->color2 >> 8) & 0xFF, (theme->color2 >> 0) & 0xFF);
3515         PRVM_clientglobalfloat(particle_tex) = (prvm_vec_t)theme->tex;
3516         PRVM_clientglobalfloat(particle_size) = theme->size;
3517         PRVM_clientglobalfloat(particle_sizeincrease) = theme->sizeincrease;
3518         PRVM_clientglobalfloat(particle_alpha) = theme->alpha/256;
3519         PRVM_clientglobalfloat(particle_alphafade) = theme->alphafade/256;
3520         PRVM_clientglobalfloat(particle_time) = theme->lifetime;
3521         PRVM_clientglobalfloat(particle_gravity) = theme->gravity;
3522         PRVM_clientglobalfloat(particle_bounce) = theme->bounce;
3523         PRVM_clientglobalfloat(particle_airfriction) = theme->airfriction;
3524         PRVM_clientglobalfloat(particle_liquidfriction) = theme->liquidfriction;
3525         PRVM_clientglobalfloat(particle_originjitter) = theme->originjitter;
3526         PRVM_clientglobalfloat(particle_velocityjitter) = theme->velocityjitter;
3527         PRVM_clientglobalfloat(particle_qualityreduction) = theme->qualityreduction;
3528         PRVM_clientglobalfloat(particle_stretch) = theme->stretch;
3529         VectorSet(PRVM_clientglobalvector(particle_staincolor1), ((int)theme->staincolor1 >> 16) & 0xFF, ((int)theme->staincolor1 >> 8) & 0xFF, ((int)theme->staincolor1 >> 0) & 0xFF);
3530         VectorSet(PRVM_clientglobalvector(particle_staincolor2), ((int)theme->staincolor2 >> 16) & 0xFF, ((int)theme->staincolor2 >> 8) & 0xFF, ((int)theme->staincolor2 >> 0) & 0xFF);
3531         PRVM_clientglobalfloat(particle_staintex) = (prvm_vec_t)theme->staintex;
3532         PRVM_clientglobalfloat(particle_stainalpha) = (prvm_vec_t)theme->stainalpha/256;
3533         PRVM_clientglobalfloat(particle_stainsize) = (prvm_vec_t)theme->stainsize;
3534         PRVM_clientglobalfloat(particle_delayspawn) = theme->delayspawn;
3535         PRVM_clientglobalfloat(particle_delaycollision) = theme->delaycollision;
3536         PRVM_clientglobalfloat(particle_angle) = theme->angle;
3537         PRVM_clientglobalfloat(particle_spin) = theme->spin;
3538 }
3539
3540 // QC globals ->  particle theme
3541 static void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme, prvm_prog_t *prog)
3542 {
3543         theme->typeindex = (unsigned short)PRVM_clientglobalfloat(particle_type);
3544         theme->blendmode = (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode);
3545         theme->orientation = (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation);
3546         theme->color1 = ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]);
3547         theme->color2 = ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]);
3548         theme->tex = (int)PRVM_clientglobalfloat(particle_tex);
3549         theme->size = PRVM_clientglobalfloat(particle_size);
3550         theme->sizeincrease = PRVM_clientglobalfloat(particle_sizeincrease);
3551         theme->alpha = PRVM_clientglobalfloat(particle_alpha)*256;
3552         theme->alphafade = PRVM_clientglobalfloat(particle_alphafade)*256;
3553         theme->lifetime = PRVM_clientglobalfloat(particle_time);
3554         theme->gravity = PRVM_clientglobalfloat(particle_gravity);
3555         theme->bounce = PRVM_clientglobalfloat(particle_bounce);
3556         theme->airfriction = PRVM_clientglobalfloat(particle_airfriction);
3557         theme->liquidfriction = PRVM_clientglobalfloat(particle_liquidfriction);
3558         theme->originjitter = PRVM_clientglobalfloat(particle_originjitter);
3559         theme->velocityjitter = PRVM_clientglobalfloat(particle_velocityjitter);
3560         theme->qualityreduction = PRVM_clientglobalfloat(particle_qualityreduction) != 0 ? true : false;
3561         theme->stretch = PRVM_clientglobalfloat(particle_stretch);
3562         theme->staincolor1 = ((int)PRVM_clientglobalvector(particle_staincolor1)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor1)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor1)[2]);
3563         theme->staincolor2 = (int)(PRVM_clientglobalvector(particle_staincolor2)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor2)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor2)[2]);
3564         theme->staintex =(int)PRVM_clientglobalfloat(particle_staintex);
3565         theme->stainalpha = PRVM_clientglobalfloat(particle_stainalpha)*256;
3566         theme->stainsize = PRVM_clientglobalfloat(particle_stainsize);
3567         theme->delayspawn = PRVM_clientglobalfloat(particle_delayspawn);
3568         theme->delaycollision = PRVM_clientglobalfloat(particle_delaycollision);
3569         theme->angle = PRVM_clientglobalfloat(particle_angle);
3570         theme->spin = PRVM_clientglobalfloat(particle_spin);
3571 }
3572
3573 // init particle spawner interface
3574 // # float(float max_themes) initparticlespawner
3575 static void VM_CL_InitParticleSpawner (prvm_prog_t *prog)
3576 {
3577         VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner);
3578         VM_InitParticleSpawner(prog, (int)PRVM_G_FLOAT(OFS_PARM0));
3579         vmpartspawner.themes[0].initialized = true;
3580         VM_ResetParticleTheme(&vmpartspawner.themes[0]);
3581         PRVM_G_FLOAT(OFS_RETURN) = (vmpartspawner.verified == true) ? 1 : 0;
3582 }
3583
3584 // void() resetparticle
3585 static void VM_CL_ResetParticle (prvm_prog_t *prog)
3586 {
3587         VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle);
3588         if (vmpartspawner.verified == false)
3589         {
3590                 VM_Warning(prog, "VM_CL_ResetParticle: particle spawner not initialized\n");
3591                 return;
3592         }
3593         VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3594 }
3595
3596 // void(float themenum) particletheme
3597 static void VM_CL_ParticleTheme (prvm_prog_t *prog)
3598 {
3599         int themenum;
3600
3601         VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme);
3602         if (vmpartspawner.verified == false)
3603         {
3604                 VM_Warning(prog, "VM_CL_ParticleTheme: particle spawner not initialized\n");
3605                 return;
3606         }
3607         themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
3608         if (themenum < 0 || themenum >= vmpartspawner.max_themes)
3609         {
3610                 VM_Warning(prog, "VM_CL_ParticleTheme: bad theme number %i\n", themenum);
3611                 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3612                 return;
3613         }
3614         if (vmpartspawner.themes[themenum].initialized == false)
3615         {
3616                 VM_Warning(prog, "VM_CL_ParticleTheme: theme #%i not exists\n", themenum);
3617                 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3618                 return;
3619         }
3620         // load particle theme into globals
3621         VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[themenum], prog);
3622 }
3623
3624 // float() saveparticletheme
3625 // void(float themenum) updateparticletheme
3626 static void VM_CL_ParticleThemeSave (prvm_prog_t *prog)
3627 {
3628         int themenum;
3629
3630         VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave);
3631         if (vmpartspawner.verified == false)
3632         {
3633                 VM_Warning(prog, "VM_CL_ParticleThemeSave: particle spawner not initialized\n");
3634                 return;
3635         }
3636         // allocate new theme, save it and return
3637         if (prog->argc < 1)
3638         {
3639                 for (themenum = 0; themenum < vmpartspawner.max_themes; themenum++)
3640                         if (vmpartspawner.themes[themenum].initialized == false)
3641                                 break;
3642                 if (themenum >= vmpartspawner.max_themes)
3643                 {
3644                         if (vmpartspawner.max_themes == 2048)
3645                                 VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots\n");
3646                         else
3647                                 VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n");
3648                         PRVM_G_FLOAT(OFS_RETURN) = -1;
3649                         return;
3650                 }
3651                 vmpartspawner.themes[themenum].initialized = true;
3652                 VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum], prog);
3653                 PRVM_G_FLOAT(OFS_RETURN) = themenum;
3654                 return;
3655         }
3656         // update existing theme
3657         themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
3658         if (themenum < 0 || themenum >= vmpartspawner.max_themes)
3659         {
3660                 VM_Warning(prog, "VM_CL_ParticleThemeSave: bad theme number %i\n", themenum);
3661                 return;
3662         }
3663         vmpartspawner.themes[themenum].initialized = true;
3664         VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum], prog);
3665 }
3666
3667 // void(float themenum) freeparticletheme
3668 static void VM_CL_ParticleThemeFree (prvm_prog_t *prog)
3669 {
3670         int themenum;
3671
3672         VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree);
3673         if (vmpartspawner.verified == false)
3674         {
3675                 VM_Warning(prog, "VM_CL_ParticleThemeFree: particle spawner not initialized\n");
3676                 return;
3677         }
3678         themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
3679         // check parms
3680         if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
3681         {
3682                 VM_Warning(prog, "VM_CL_ParticleThemeFree: bad theme number %i\n", themenum);
3683                 return;
3684         }
3685         if (vmpartspawner.themes[themenum].initialized == false)
3686         {
3687                 VM_Warning(prog, "VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum);
3688                 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3689                 return;
3690         }
3691         // free theme
3692         VM_ResetParticleTheme(&vmpartspawner.themes[themenum]);
3693         vmpartspawner.themes[themenum].initialized = false;
3694 }
3695
3696 // float(vector org, vector dir, [float theme]) particle
3697 // returns 0 if failed, 1 if succesful
3698 static void VM_CL_SpawnParticle (prvm_prog_t *prog)
3699 {
3700         vec3_t org, dir;
3701         vmparticletheme_t *theme;
3702         particle_t *part;
3703         int themenum;
3704
3705         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle);
3706         if (vmpartspawner.verified == false)
3707         {
3708                 VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n");
3709                 PRVM_G_FLOAT(OFS_RETURN) = 0;
3710                 return;
3711         }
3712         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
3713         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
3714
3715         if (prog->argc < 3) // global-set particle
3716         {
3717                 part = CL_NewParticle(org,
3718                         (unsigned short)PRVM_clientglobalfloat(particle_type),
3719                         ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]),
3720                         ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]),
3721                         (int)PRVM_clientglobalfloat(particle_tex),
3722                         PRVM_clientglobalfloat(particle_size),
3723                         PRVM_clientglobalfloat(particle_sizeincrease),
3724                         PRVM_clientglobalfloat(particle_alpha)*256,
3725                         PRVM_clientglobalfloat(particle_alphafade)*256,
3726                         PRVM_clientglobalfloat(particle_gravity),
3727                         PRVM_clientglobalfloat(particle_bounce),
3728                         org[0],
3729                         org[1],
3730                         org[2],
3731                         dir[0],
3732                         dir[1],
3733                         dir[2],
3734                         PRVM_clientglobalfloat(particle_airfriction),
3735                         PRVM_clientglobalfloat(particle_liquidfriction),
3736                         PRVM_clientglobalfloat(particle_originjitter),
3737                         PRVM_clientglobalfloat(particle_velocityjitter),
3738                         (PRVM_clientglobalfloat(particle_qualityreduction)) ? true : false,
3739                         PRVM_clientglobalfloat(particle_time),
3740                         PRVM_clientglobalfloat(particle_stretch),
3741                         (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode),
3742                         (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation),
3743                         (int)(PRVM_clientglobalvector(particle_staincolor1)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor1)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor1)[2]),
3744                         (int)(PRVM_clientglobalvector(particle_staincolor2)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor2)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor2)[2]),
3745                         (int)PRVM_clientglobalfloat(particle_staintex),
3746                         PRVM_clientglobalfloat(particle_stainalpha)*256,
3747                         PRVM_clientglobalfloat(particle_stainsize),
3748                         PRVM_clientglobalfloat(particle_angle),
3749                         PRVM_clientglobalfloat(particle_spin),
3750                         NULL);
3751                 if (!part)
3752                 {
3753                         PRVM_G_FLOAT(OFS_RETURN) = 0;
3754                         return;
3755                 }
3756                 if (PRVM_clientglobalfloat(particle_delayspawn))
3757                         part->delayedspawn = cl.time + PRVM_clientglobalfloat(particle_delayspawn);
3758                 //if (PRVM_clientglobalfloat(particle_delaycollision))
3759                 //      part->delayedcollisions = cl.time + PRVM_clientglobalfloat(particle_delaycollision);
3760         }
3761         else // quick themed particle
3762         {
3763                 themenum = (int)PRVM_G_FLOAT(OFS_PARM2);
3764                 if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
3765                 {
3766                         VM_Warning(prog, "VM_CL_SpawnParticle: bad theme number %i\n", themenum);
3767                         PRVM_G_FLOAT(OFS_RETURN) = 0;
3768                         return;
3769                 }
3770                 theme = &vmpartspawner.themes[themenum];
3771                 part = CL_NewParticle(org,
3772                         theme->typeindex,
3773                         theme->color1,
3774                         theme->color2,
3775                         theme->tex,
3776                         theme->size,
3777                         theme->sizeincrease,
3778                         theme->alpha,
3779                         theme->alphafade,
3780                         theme->gravity,
3781                         theme->bounce,
3782                         org[0],
3783                         org[1],
3784                         org[2],
3785                         dir[0],
3786                         dir[1],
3787                         dir[2],
3788                         theme->airfriction,
3789                         theme->liquidfriction,
3790                         theme->originjitter,
3791                         theme->velocityjitter,
3792                         theme->qualityreduction,
3793                         theme->lifetime,
3794                         theme->stretch,
3795                         theme->blendmode,
3796                         theme->orientation,
3797                         theme->staincolor1,
3798                         theme->staincolor2,
3799                         theme->staintex,
3800                         theme->stainalpha,
3801                         theme->stainsize,
3802                         theme->angle,
3803                         theme->spin,
3804                         NULL);
3805                 if (!part)
3806                 {
3807                         PRVM_G_FLOAT(OFS_RETURN) = 0;
3808                         return;
3809                 }
3810                 if (theme->delayspawn)
3811                         part->delayedspawn = cl.time + theme->delayspawn;
3812                 //if (theme->delaycollision)
3813                 //      part->delayedcollisions = cl.time + theme->delaycollision;
3814         }
3815         PRVM_G_FLOAT(OFS_RETURN) = 1;
3816 }
3817
3818 // float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle
3819 // returns 0 if failed, 1 if success
3820 static void VM_CL_SpawnParticleDelayed (prvm_prog_t *prog)
3821 {
3822         vec3_t org, dir;
3823         vmparticletheme_t *theme;
3824         particle_t *part;
3825         int themenum;
3826
3827         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticleDelayed);
3828         if (vmpartspawner.verified == false)
3829         {
3830                 VM_Warning(prog, "VM_CL_SpawnParticleDelayed: particle spawner not initialized\n");
3831                 PRVM_G_FLOAT(OFS_RETURN) = 0;
3832                 return;
3833         }
3834         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
3835         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
3836         if (prog->argc < 5) // global-set particle
3837                 part = CL_NewParticle(org,
3838                         (unsigned short)PRVM_clientglobalfloat(particle_type),
3839                         ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]),
3840                         ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]),
3841                         (int)PRVM_clientglobalfloat(particle_tex),
3842                         PRVM_clientglobalfloat(particle_size),
3843                         PRVM_clientglobalfloat(particle_sizeincrease),
3844                         PRVM_clientglobalfloat(particle_alpha)*256,
3845                         PRVM_clientglobalfloat(particle_alphafade)*256,
3846                         PRVM_clientglobalfloat(particle_gravity),
3847                         PRVM_clientglobalfloat(particle_bounce),
3848                         org[0],
3849                         org[1],
3850                         org[2],
3851                         dir[0],
3852                         dir[1],
3853                         dir[2],
3854                         PRVM_clientglobalfloat(particle_airfriction),
3855                         PRVM_clientglobalfloat(particle_liquidfriction),
3856                         PRVM_clientglobalfloat(particle_originjitter),
3857                         PRVM_clientglobalfloat(particle_velocityjitter),
3858                         (PRVM_clientglobalfloat(particle_qualityreduction)) ? true : false,
3859                         PRVM_clientglobalfloat(particle_time),
3860                         PRVM_clientglobalfloat(particle_stretch),
3861                         (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode),
3862                         (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation),
3863                         ((int)PRVM_clientglobalvector(particle_staincolor1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_staincolor1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_staincolor1)[2]),
3864                         ((int)PRVM_clientglobalvector(particle_staincolor2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_staincolor2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_staincolor2)[2]),
3865                         (int)PRVM_clientglobalfloat(particle_staintex),
3866                         PRVM_clientglobalfloat(particle_stainalpha)*256,
3867                         PRVM_clientglobalfloat(particle_stainsize),
3868                         PRVM_clientglobalfloat(particle_angle),
3869                         PRVM_clientglobalfloat(particle_spin),
3870                         NULL);
3871         else // themed particle
3872         {
3873                 themenum = (int)PRVM_G_FLOAT(OFS_PARM4);
3874                 if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
3875                 {
3876                         VM_Warning(prog, "VM_CL_SpawnParticleDelayed: bad theme number %i\n", themenum);
3877                         PRVM_G_FLOAT(OFS_RETURN) = 0;
3878                         return;
3879                 }
3880                 theme = &vmpartspawner.themes[themenum];
3881                 part = CL_NewParticle(org,
3882                         theme->typeindex,
3883                         theme->color1,
3884                         theme->color2,
3885                         theme->tex,
3886                         theme->size,
3887                         theme->sizeincrease,
3888                         theme->alpha,
3889                         theme->alphafade,
3890                         theme->gravity,
3891                         theme->bounce,
3892                         org[0],
3893                         org[1],
3894                         org[2],
3895                         dir[0],
3896                         dir[1],
3897                         dir[2],
3898                         theme->airfriction,
3899                         theme->liquidfriction,
3900                         theme->originjitter,
3901                         theme->velocityjitter,
3902                         theme->qualityreduction,
3903                         theme->lifetime,
3904                         theme->stretch,
3905                         theme->blendmode,
3906                         theme->orientation,
3907                         theme->staincolor1,
3908                         theme->staincolor2,
3909                         theme->staintex,
3910                         theme->stainalpha,
3911                         theme->stainsize,
3912                         theme->angle,
3913                         theme->spin,
3914                         NULL);
3915         }
3916         if (!part)
3917         {
3918                 PRVM_G_FLOAT(OFS_RETURN) = 0;
3919                 return;
3920         }
3921         part->delayedspawn = cl.time + PRVM_G_FLOAT(OFS_PARM2);
3922         //part->delayedcollisions = cl.time + PRVM_G_FLOAT(OFS_PARM3);
3923         PRVM_G_FLOAT(OFS_RETURN) = 0;
3924 }
3925
3926 //====================
3927 //CSQC engine entities query
3928 //====================
3929
3930 // float(float entitynum, float whatfld) getentity;
3931 // vector(float entitynum, float whatfld) getentityvec;
3932 // querying engine-drawn entity
3933 // VorteX: currently it's only tested with whatfld = 1..7
3934 static void VM_CL_GetEntity (prvm_prog_t *prog)
3935 {
3936         int entnum, fieldnum;
3937         vec3_t forward, left, up, org;
3938         VM_SAFEPARMCOUNT(2, VM_CL_GetEntity);
3939
3940         entnum = PRVM_G_FLOAT(OFS_PARM0);
3941         if (entnum < 0 || entnum >= cl.num_entities)
3942         {
3943                 PRVM_G_FLOAT(OFS_RETURN) = 0;
3944                 return;
3945         }
3946         fieldnum = PRVM_G_FLOAT(OFS_PARM1);
3947         switch(fieldnum)
3948         {
3949                 case 0: // active state
3950                         PRVM_G_FLOAT(OFS_RETURN) = cl.entities_active[entnum];
3951                         break;
3952                 case 1: // origin
3953                         Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
3954                         VectorCopy(org, PRVM_G_VECTOR(OFS_RETURN));
3955                         break;
3956                 case 2: // forward
3957                         Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3958                         VectorCopy(forward, PRVM_G_VECTOR(OFS_RETURN));
3959                         break;
3960                 case 3: // right
3961                         Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3962                         VectorNegate(left, PRVM_G_VECTOR(OFS_RETURN));
3963                         break;
3964                 case 4: // up
3965                         Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3966                         VectorCopy(up, PRVM_G_VECTOR(OFS_RETURN));
3967                         break;
3968                 case 5: // scale
3969                         PRVM_G_FLOAT(OFS_RETURN) = Matrix4x4_ScaleFromMatrix(&cl.entities[entnum].render.matrix);
3970                         break;
3971                 case 6: // origin + v_forward, v_right, v_up
3972                         Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3973                         VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3974                         VectorNegate(left, PRVM_clientglobalvector(v_right));
3975                         VectorCopy(up, PRVM_clientglobalvector(v_up));
3976                         VectorCopy(org, PRVM_G_VECTOR(OFS_RETURN));
3977                         break;
3978                 case 7: // alpha
3979                         PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.alpha;
3980                         break;
3981                 case 8: // colormor
3982                         VectorCopy(cl.entities[entnum].render.colormod, PRVM_G_VECTOR(OFS_RETURN));
3983                         break;
3984                 case 9: // pants colormod
3985                         VectorCopy(cl.entities[entnum].render.colormap_pantscolor, PRVM_G_VECTOR(OFS_RETURN));
3986                         break;
3987                 case 10: // shirt colormod
3988                         VectorCopy(cl.entities[entnum].render.colormap_shirtcolor, PRVM_G_VECTOR(OFS_RETURN));
3989                         break;
3990                 case 11: // skinnum
3991                         PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.skinnum;
3992                         break;
3993                 case 12: // mins
3994                         VectorCopy(cl.entities[entnum].render.mins, PRVM_G_VECTOR(OFS_RETURN));
3995                         break;
3996                 case 13: // maxs
3997                         VectorCopy(cl.entities[entnum].render.maxs, PRVM_G_VECTOR(OFS_RETURN));
3998                         break;
3999                 case 14: // absmin
4000                         Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
4001                         VectorAdd(cl.entities[entnum].render.mins, org, PRVM_G_VECTOR(OFS_RETURN));
4002                         break;
4003                 case 15: // absmax
4004                         Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
4005                         VectorAdd(cl.entities[entnum].render.maxs, org, PRVM_G_VECTOR(OFS_RETURN));
4006                         break;
4007                 case 16: // light
4008                         VectorMA(cl.entities[entnum].render.render_modellight_ambient, 0.5, cl.entities[entnum].render.render_modellight_diffuse, PRVM_G_VECTOR(OFS_RETURN));
4009                         break;
4010                 default:
4011                         PRVM_G_FLOAT(OFS_RETURN) = 0;
4012                         break;
4013         }
4014 }
4015
4016 //====================
4017 //QC POLYGON functions
4018 //====================
4019
4020 //#304 void() renderscene (EXT_CSQC)
4021 // moved that here to reset the polygons,
4022 // resetting them earlier causes R_Mesh_Draw to be called with numvertices = 0
4023 // --blub
4024 static void VM_CL_R_RenderScene (prvm_prog_t *prog)
4025 {
4026         qbool ismain = r_refdef.view.ismain;
4027         double t = Sys_DirtyTime();
4028         VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
4029
4030         // update the views
4031         if(ismain)
4032         {
4033                 // set the main view
4034                 csqc_main_r_refdef_view = r_refdef.view;
4035         }
4036
4037         // now after all of the predraw we know the geometry in the scene mesh and can finalize it for rendering
4038         CL_MeshEntities_Scene_FinalizeRenderEntity();
4039
4040         // we need to update any RENDER_VIEWMODEL entities at this point because
4041         // csqc supplies its own view matrix
4042         CL_UpdateViewEntities();
4043         CL_UpdateEntityShading();
4044
4045         // now draw stuff!
4046         R_RenderView(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4047
4048         // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
4049         t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
4050         prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
4051
4052         // polygonbegin without draw2d arg has to guess
4053         prog->polygonbegin_guess2d = false;
4054
4055         // update the views
4056         if (ismain)
4057         {
4058                 // clear the flags so no other view becomes "main" unless CSQC sets VF_MAINVIEW
4059                 r_refdef.view.ismain = false;
4060                 csqc_original_r_refdef_view.ismain = false;
4061         }
4062 }
4063
4064 //void(string texturename, float flag[, float is2d]) R_BeginPolygon
4065 static void VM_CL_R_PolygonBegin (prvm_prog_t *prog)
4066 {
4067         const char *texname;
4068         int drawflags;
4069         qbool draw2d;
4070         model_t *mod;
4071
4072         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_PolygonBegin);
4073
4074         texname = PRVM_G_STRING(OFS_PARM0);
4075         drawflags = (int)PRVM_G_FLOAT(OFS_PARM1);
4076         if (prog->argc >= 3)
4077                 draw2d = PRVM_G_FLOAT(OFS_PARM2) != 0;
4078         else
4079         {
4080                 // weird hacky way to figure out if this is a 2D HUD polygon or a scene
4081                 // polygon, for compatibility with mods aimed at old darkplaces versions
4082                 // - polygonbegin_guess2d is 0 if the most recent major call was
4083                 // clearscene, 1 if the most recent major call was drawpic (and similar)
4084                 // or renderscene
4085                 draw2d = prog->polygonbegin_guess2d;
4086         }
4087
4088         // we need to remember whether this is a 2D or 3D mesh we're adding to
4089         mod = draw2d ? CL_Mesh_UI() : CL_Mesh_Scene();
4090         prog->polygonbegin_model = mod;
4091         if (texname == NULL || texname[0] == 0)
4092                 texname = "$whiteimage";
4093         strlcpy(prog->polygonbegin_texname, texname, sizeof(prog->polygonbegin_texname));
4094         prog->polygonbegin_drawflags = drawflags;
4095         prog->polygonbegin_numvertices = 0;
4096 }
4097
4098 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
4099 static void VM_CL_R_PolygonVertex (prvm_prog_t *prog)
4100 {
4101         const prvm_vec_t *v = PRVM_G_VECTOR(OFS_PARM0);
4102         const prvm_vec_t *tc = PRVM_G_VECTOR(OFS_PARM1);
4103         const prvm_vec_t *c = PRVM_G_VECTOR(OFS_PARM2);
4104         const prvm_vec_t a = PRVM_G_FLOAT(OFS_PARM3);
4105         float *o;
4106         model_t *mod = prog->polygonbegin_model;
4107
4108         VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
4109
4110         if (!mod)
4111         {
4112                 VM_Warning(prog, "VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
4113                 return;
4114         }
4115
4116         if (prog->polygonbegin_maxvertices <= prog->polygonbegin_numvertices)
4117         {
4118                 prog->polygonbegin_maxvertices = max(16, prog->polygonbegin_maxvertices * 2);
4119                 prog->polygonbegin_vertexdata = (float *)Mem_Realloc(prog->progs_mempool, prog->polygonbegin_vertexdata, prog->polygonbegin_maxvertices * sizeof(float[10]));
4120         }
4121         o = prog->polygonbegin_vertexdata + prog->polygonbegin_numvertices++ * 10;
4122
4123         o[0] = v[0];
4124         o[1] = v[1];
4125         o[2] = v[2];
4126         o[3] = tc[0];
4127         o[4] = tc[1];
4128         o[5] = tc[2];
4129         o[6] = c[0];
4130         o[7] = c[1];
4131         o[8] = c[2];
4132         o[9] = a;
4133 }
4134
4135 //void() R_EndPolygon
4136 static void VM_CL_R_PolygonEnd (prvm_prog_t *prog)
4137 {
4138         int i;
4139         qbool hascolor;
4140         qbool hasalpha;
4141         int e0 = 0, e1 = 0, e2 = 0;
4142         float *o;
4143         model_t *mod = prog->polygonbegin_model;
4144         msurface_t *surf;
4145         texture_t *tex;
4146         int materialflags;
4147
4148         VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
4149         if (!mod)
4150         {
4151                 VM_Warning(prog, "VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
4152                 return;
4153         }
4154
4155         // determine if vertex alpha is being used so we can provide that hint to GetTexture...
4156         hascolor = false;
4157         hasalpha = false;
4158         for (i = 0; i < prog->polygonbegin_numvertices; i++)
4159         {
4160                 o = prog->polygonbegin_vertexdata + 10 * i;
4161                 if (o[6] != 1.0f || o[7] != 1.0f || o[8] != 1.0f)
4162                         hascolor = true;
4163                 if (o[9] != 1.0f)
4164                         hasalpha = true;
4165         }
4166
4167         // create the surface, looking up the best matching texture/shader
4168         materialflags = MATERIALFLAG_WALL;
4169         if (csqc_polygons_defaultmaterial_nocullface.integer)
4170                 materialflags |= MATERIALFLAG_NOCULLFACE;
4171         if (hascolor)
4172                 materialflags |= MATERIALFLAG_VERTEXCOLOR;
4173         if (hasalpha)
4174                 materialflags |= MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
4175         tex = Mod_Mesh_GetTexture(mod, prog->polygonbegin_texname, prog->polygonbegin_drawflags, TEXF_ALPHA, materialflags);
4176         surf = Mod_Mesh_AddSurface(mod, tex, false);
4177         // create triangle fan
4178         for (i = 0; i < prog->polygonbegin_numvertices; i++)
4179         {
4180                 o = prog->polygonbegin_vertexdata + 10 * i;
4181                 e2 = Mod_Mesh_IndexForVertex(mod, surf, o[0], o[1], o[2], 0, 0, 0, o[3], o[4], 0, 0, o[6], o[7], o[8], o[9]);
4182                 if (i >= 2)
4183                         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
4184                 else if (i == 0)
4185                         e0 = e2;
4186                 e1 = e2;
4187         }
4188         // build normals (since they are not provided)
4189         Mod_BuildNormals(surf->num_firstvertex, surf->num_vertices, surf->num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_element3i + 3 * surf->num_firsttriangle, mod->surfmesh.data_normal3f, true);
4190
4191         // reset state
4192         prog->polygonbegin_model = NULL;
4193         prog->polygonbegin_texname[0] = 0;
4194         prog->polygonbegin_drawflags = 0;
4195         prog->polygonbegin_numvertices = 0;
4196 }
4197
4198 /*
4199 =============
4200 CL_CheckBottom
4201
4202 Returns false if any part of the bottom of the entity is off an edge that
4203 is not a staircase.
4204
4205 =============
4206 */
4207 static qbool CL_CheckBottom (prvm_edict_t *ent)
4208 {
4209         prvm_prog_t *prog = CLVM_prog;
4210         vec3_t  mins, maxs, start, stop;
4211         trace_t trace;
4212         int             x, y;
4213         float   mid, bottom;
4214
4215         VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
4216         VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
4217
4218 // if all of the points under the corners are solid world, don't bother
4219 // with the tougher checks
4220 // the corners must be within 16 of the midpoint
4221         start[2] = mins[2] - 1;
4222         for     (x=0 ; x<=1 ; x++)
4223                 for     (y=0 ; y<=1 ; y++)
4224                 {
4225                         start[0] = x ? maxs[0] : mins[0];
4226                         start[1] = y ? maxs[1] : mins[1];
4227                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
4228                                 goto realcheck;
4229                 }
4230
4231         return true;            // we got out easy
4232
4233 realcheck:
4234 //
4235 // check it for real...
4236 //
4237         start[2] = mins[2];
4238
4239 // the midpoint must be within 16 of the bottom
4240         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
4241         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
4242         stop[2] = start[2] - 2*sv_stepheight.value;
4243         trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, false, NULL, true, false);
4244
4245         if (trace.fraction == 1.0)
4246                 return false;
4247         mid = bottom = trace.endpos[2];
4248
4249 // the corners must be within 16 of the midpoint
4250         for     (x=0 ; x<=1 ; x++)
4251                 for     (y=0 ; y<=1 ; y++)
4252                 {
4253                         start[0] = stop[0] = x ? maxs[0] : mins[0];
4254                         start[1] = stop[1] = y ? maxs[1] : mins[1];
4255
4256                         trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, false, NULL, true, false);
4257
4258                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
4259                                 bottom = trace.endpos[2];
4260                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
4261                                 return false;
4262                 }
4263
4264         return true;
4265 }
4266
4267 /*
4268 =============
4269 CL_movestep
4270
4271 Called by monster program code.
4272 The move will be adjusted for slopes and stairs, but if the move isn't
4273 possible, no move is done and false is returned
4274 =============
4275 */
4276 static qbool CL_movestep (prvm_edict_t *ent, vec3_t move, qbool relink, qbool noenemy, qbool settrace)
4277 {
4278         prvm_prog_t *prog = CLVM_prog;
4279         float           dz;
4280         vec3_t          oldorg, neworg, end, traceendpos;
4281         vec3_t          mins, maxs, start;
4282         trace_t         trace;
4283         int                     i, svent;
4284         prvm_edict_t            *enemy;
4285
4286 // try the move
4287         VectorCopy(PRVM_clientedictvector(ent, mins), mins);
4288         VectorCopy(PRVM_clientedictvector(ent, maxs), maxs);
4289         VectorCopy (PRVM_clientedictvector(ent, origin), oldorg);
4290         VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg);
4291
4292 // flying monsters don't step up
4293         if ( (int)PRVM_clientedictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
4294         {
4295         // try one move with vertical motion, then one without
4296                 for (i=0 ; i<2 ; i++)
4297                 {
4298                         VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg);
4299                         enemy = PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy));
4300                         if (i == 0 && enemy != prog->edicts)
4301                         {
4302                                 dz = PRVM_clientedictvector(ent, origin)[2] - PRVM_clientedictvector(PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy)), origin)[2];
4303                                 if (dz > 40)
4304                                         neworg[2] -= 8;
4305                                 if (dz < 30)
4306                                         neworg[2] += 8;
4307                         }
4308                         VectorCopy(PRVM_clientedictvector(ent, origin), start);
4309                         trace = CL_TraceBox(start, mins, maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, &svent, true);
4310                         if (settrace)
4311                                 CL_VM_SetTraceGlobals(prog, &trace, svent);
4312
4313                         if (trace.fraction == 1)
4314                         {
4315                                 VectorCopy(trace.endpos, traceendpos);
4316                                 if (((int)PRVM_clientedictfloat(ent, flags) & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
4317                                         return false;   // swim monster left water
4318
4319                                 VectorCopy (traceendpos, PRVM_clientedictvector(ent, origin));
4320                                 if (relink)
4321                                         CL_LinkEdict(ent);
4322                                 return true;
4323                         }
4324
4325                         if (enemy == prog->edicts)
4326                                 break;
4327                 }
4328
4329                 return false;
4330         }
4331
4332 // push down from a step height above the wished position
4333         neworg[2] += sv_stepheight.value;
4334         VectorCopy (neworg, end);
4335         end[2] -= sv_stepheight.value*2;
4336
4337         trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, &svent, true);
4338         if (settrace)
4339                 CL_VM_SetTraceGlobals(prog, &trace, svent);
4340
4341         if (trace.startsolid)
4342         {
4343                 neworg[2] -= sv_stepheight.value;
4344                 trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, &svent, true);
4345                 if (settrace)
4346                         CL_VM_SetTraceGlobals(prog, &trace, svent);
4347                 if (trace.startsolid)
4348                         return false;
4349         }
4350         if (trace.fraction == 1)
4351         {
4352         // if monster had the ground pulled out, go ahead and fall
4353                 if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
4354                 {
4355                         VectorAdd (PRVM_clientedictvector(ent, origin), move, PRVM_clientedictvector(ent, origin));
4356                         if (relink)
4357                                 CL_LinkEdict(ent);
4358                         PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_ONGROUND;
4359                         return true;
4360                 }
4361
4362                 return false;           // walked off an edge
4363         }
4364
4365 // check point traces down for dangling corners
4366         VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin));
4367
4368         if (!CL_CheckBottom (ent))
4369         {
4370                 if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
4371                 {       // entity had floor mostly pulled out from underneath it
4372                         // and is trying to correct
4373                         if (relink)
4374                                 CL_LinkEdict(ent);
4375                         return true;
4376                 }
4377                 VectorCopy (oldorg, PRVM_clientedictvector(ent, origin));
4378                 return false;
4379         }
4380
4381         if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
4382                 PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_PARTIALGROUND;
4383
4384         PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
4385
4386 // the move is ok
4387         if (relink)
4388                 CL_LinkEdict(ent);
4389         return true;
4390 }
4391
4392 /*
4393 ===============
4394 VM_CL_walkmove
4395
4396 float(float yaw, float dist[, settrace]) walkmove
4397 ===============
4398 */
4399 static void VM_CL_walkmove (prvm_prog_t *prog)
4400 {
4401         prvm_edict_t    *ent;
4402         float   yaw, dist;
4403         vec3_t  move;
4404         mfunction_t     *oldf;
4405         int     oldself;
4406         qbool   settrace;
4407
4408         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
4409
4410         // assume failure if it returns early
4411         PRVM_G_FLOAT(OFS_RETURN) = 0;
4412
4413         ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
4414         if (ent == prog->edicts)
4415         {
4416                 VM_Warning(prog, "walkmove: can not modify world entity\n");
4417                 return;
4418         }
4419         if (ent->priv.server->free)
4420         {
4421                 VM_Warning(prog, "walkmove: can not modify free entity\n");
4422                 return;
4423         }
4424         yaw = PRVM_G_FLOAT(OFS_PARM0);
4425         dist = PRVM_G_FLOAT(OFS_PARM1);
4426         settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
4427
4428         if ( !( (int)PRVM_clientedictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
4429                 return;
4430
4431         yaw = yaw*M_PI*2 / 360;
4432
4433         move[0] = cos(yaw)*dist;
4434         move[1] = sin(yaw)*dist;
4435         move[2] = 0;
4436
4437 // save program state, because CL_movestep may call other progs
4438         oldf = prog->xfunction;
4439         oldself = PRVM_clientglobaledict(self);
4440
4441         PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
4442
4443
4444 // restore program state
4445         prog->xfunction = oldf;
4446         PRVM_clientglobaledict(self) = oldself;
4447 }
4448
4449 /*
4450 ===============
4451 VM_CL_serverkey
4452
4453 string(string key) serverkey
4454 ===============
4455 */
4456 static void VM_CL_serverkey(prvm_prog_t *prog)
4457 {
4458         char string[VM_STRINGTEMP_LENGTH];
4459         VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
4460         InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
4461         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
4462 }
4463
4464 /*
4465 =================
4466 VM_CL_checkpvs
4467
4468 Checks if an entity is in a point's PVS.
4469 Should be fast but can be inexact.
4470
4471 float checkpvs(vector viewpos, entity viewee) = #240;
4472 =================
4473 */
4474 static void VM_CL_checkpvs (prvm_prog_t *prog)
4475 {
4476         vec3_t viewpos;
4477         prvm_edict_t *viewee;
4478         vec3_t mi, ma;
4479 #if 1
4480         unsigned char *pvs;
4481 #else
4482         int fatpvsbytes;
4483         unsigned char fatpvs[MAX_MAP_LEAFS/8];
4484 #endif
4485
4486         VM_SAFEPARMCOUNT(2, VM_CL_checkpvs);
4487         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
4488         viewee = PRVM_G_EDICT(OFS_PARM1);
4489
4490         if(viewee->priv.required->free)
4491         {
4492                 VM_Warning(prog, "checkpvs: can not check free entity\n");
4493                 PRVM_G_FLOAT(OFS_RETURN) = 4;
4494                 return;
4495         }
4496
4497         VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, mins), mi);
4498         VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, maxs), ma);
4499
4500 #if 1
4501         if(!cl.worldmodel || !cl.worldmodel->brush.GetPVS || !cl.worldmodel->brush.BoxTouchingPVS)
4502         {
4503                 // no PVS support on this worldmodel... darn
4504                 PRVM_G_FLOAT(OFS_RETURN) = 3;
4505                 return;
4506         }
4507         pvs = cl.worldmodel->brush.GetPVS(cl.worldmodel, viewpos);
4508         if(!pvs)
4509         {
4510                 // viewpos isn't in any PVS... darn
4511                 PRVM_G_FLOAT(OFS_RETURN) = 2;
4512                 return;
4513         }
4514         PRVM_G_FLOAT(OFS_RETURN) = cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, pvs, mi, ma);
4515 #else
4516         // using fat PVS like FTEQW does (slow)
4517         if(!cl.worldmodel || !cl.worldmodel->brush.FatPVS || !cl.worldmodel->brush.BoxTouchingPVS)
4518         {
4519                 // no PVS support on this worldmodel... darn
4520                 PRVM_G_FLOAT(OFS_RETURN) = 3;
4521                 return;
4522         }
4523         fatpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
4524         if(!fatpvsbytes)
4525         {
4526                 // viewpos isn't in any PVS... darn
4527                 PRVM_G_FLOAT(OFS_RETURN) = 2;
4528                 return;
4529         }
4530         PRVM_G_FLOAT(OFS_RETURN) = cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, fatpvs, mi, ma);
4531 #endif
4532 }
4533
4534 // #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure  (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex.
4535 static void VM_CL_skel_create(prvm_prog_t *prog)
4536 {
4537         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
4538         model_t *model = CL_GetModelByIndex(modelindex);
4539         skeleton_t *skeleton;
4540         int i;
4541         PRVM_G_FLOAT(OFS_RETURN) = 0;
4542         if (!model || !model->num_bones)
4543                 return;
4544         for (i = 0;i < MAX_EDICTS;i++)
4545                 if (!prog->skeletons[i])
4546                         break;
4547         if (i == MAX_EDICTS)
4548                 return;
4549         prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
4550         PRVM_G_FLOAT(OFS_RETURN) = i + 1;
4551         skeleton->model = model;
4552         skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
4553         // initialize to identity matrices
4554         for (i = 0;i < skeleton->model->num_bones;i++)
4555                 skeleton->relativetransforms[i] = identitymatrix;
4556 }
4557
4558 // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
4559 static void VM_CL_skel_build(prvm_prog_t *prog)
4560 {
4561         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4562         skeleton_t *skeleton;
4563         prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
4564         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
4565         float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
4566         int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
4567         int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
4568         model_t *model = CL_GetModelByIndex(modelindex);
4569         int numblends;
4570         int bonenum;
4571         int blendindex;
4572         framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
4573         frameblend_t frameblend[MAX_FRAMEBLENDS];
4574         matrix4x4_t bonematrix;
4575         matrix4x4_t matrix;
4576         PRVM_G_FLOAT(OFS_RETURN) = 0;
4577         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4578                 return;
4579         firstbone = max(0, firstbone);
4580         lastbone = min(lastbone, model->num_bones - 1);
4581         lastbone = min(lastbone, skeleton->model->num_bones - 1);
4582         VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
4583         VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, cl.time);
4584         for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
4585                 ;
4586         for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
4587         {
4588                 memset(&bonematrix, 0, sizeof(bonematrix));
4589                 for (blendindex = 0;blendindex < numblends;blendindex++)
4590                 {
4591                         Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
4592                         Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
4593                 }
4594                 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
4595                 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
4596         }
4597         PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
4598 }
4599
4600 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
4601 static void VM_CL_skel_get_numbones(prvm_prog_t *prog)
4602 {
4603         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4604         skeleton_t *skeleton;
4605         PRVM_G_FLOAT(OFS_RETURN) = 0;
4606         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4607                 return;
4608         PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
4609 }
4610
4611 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
4612 static void VM_CL_skel_get_bonename(prvm_prog_t *prog)
4613 {
4614         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4615         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4616         skeleton_t *skeleton;
4617         PRVM_G_INT(OFS_RETURN) = 0;
4618         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4619                 return;
4620         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4621                 return;
4622         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
4623 }
4624
4625 // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
4626 static void VM_CL_skel_get_boneparent(prvm_prog_t *prog)
4627 {
4628         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4629         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4630         skeleton_t *skeleton;
4631         PRVM_G_FLOAT(OFS_RETURN) = 0;
4632         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4633                 return;
4634         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4635                 return;
4636         PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
4637 }
4638
4639 // #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
4640 static void VM_CL_skel_find_bone(prvm_prog_t *prog)
4641 {
4642         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4643         const char *tagname = PRVM_G_STRING(OFS_PARM1);
4644         skeleton_t *skeleton;
4645         PRVM_G_FLOAT(OFS_RETURN) = 0;
4646         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4647                 return;
4648         PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname);
4649 }
4650
4651 // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
4652 static void VM_CL_skel_get_bonerel(prvm_prog_t *prog)
4653 {
4654         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4655         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4656         skeleton_t *skeleton;
4657         matrix4x4_t matrix;
4658         vec3_t forward, left, up, origin;
4659         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
4660         VectorClear(PRVM_clientglobalvector(v_forward));
4661         VectorClear(PRVM_clientglobalvector(v_right));
4662         VectorClear(PRVM_clientglobalvector(v_up));
4663         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4664                 return;
4665         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4666                 return;
4667         matrix = skeleton->relativetransforms[bonenum];
4668         Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
4669         VectorCopy(forward, PRVM_clientglobalvector(v_forward));
4670         VectorNegate(left, PRVM_clientglobalvector(v_right));
4671         VectorCopy(up, PRVM_clientglobalvector(v_up));
4672         VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
4673 }
4674
4675 // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
4676 static void VM_CL_skel_get_boneabs(prvm_prog_t *prog)
4677 {
4678         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4679         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4680         skeleton_t *skeleton;
4681         matrix4x4_t matrix;
4682         matrix4x4_t temp;
4683         vec3_t forward, left, up, origin;
4684         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
4685         VectorClear(PRVM_clientglobalvector(v_forward));
4686         VectorClear(PRVM_clientglobalvector(v_right));
4687         VectorClear(PRVM_clientglobalvector(v_up));
4688         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4689                 return;
4690         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4691                 return;
4692         matrix = skeleton->relativetransforms[bonenum];
4693         // convert to absolute
4694         while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
4695         {
4696                 temp = matrix;
4697                 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
4698         }
4699         Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
4700         VectorCopy(forward, PRVM_clientglobalvector(v_forward));
4701         VectorNegate(left, PRVM_clientglobalvector(v_right));
4702         VectorCopy(up, PRVM_clientglobalvector(v_up));
4703         VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
4704 }
4705
4706 // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
4707 static void VM_CL_skel_set_bone(prvm_prog_t *prog)
4708 {
4709         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4710         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4711         vec3_t forward, left, up, origin;
4712         skeleton_t *skeleton;
4713         matrix4x4_t matrix;
4714         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4715                 return;
4716         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4717                 return;
4718         VectorCopy(PRVM_clientglobalvector(v_forward), forward);
4719         VectorNegate(PRVM_clientglobalvector(v_right), left);
4720         VectorCopy(PRVM_clientglobalvector(v_up), up);
4721         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
4722         Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
4723         skeleton->relativetransforms[bonenum] = matrix;
4724 }
4725
4726 // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
4727 static void VM_CL_skel_mul_bone(prvm_prog_t *prog)
4728 {
4729         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4730         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4731         vec3_t forward, left, up, origin;
4732         skeleton_t *skeleton;
4733         matrix4x4_t matrix;
4734         matrix4x4_t temp;
4735         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4736                 return;
4737         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4738                 return;
4739         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
4740         VectorCopy(PRVM_clientglobalvector(v_forward), forward);
4741         VectorNegate(PRVM_clientglobalvector(v_right), left);
4742         VectorCopy(PRVM_clientglobalvector(v_up), up);
4743         Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
4744         temp = skeleton->relativetransforms[bonenum];
4745         Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
4746 }
4747
4748 // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
4749 static void VM_CL_skel_mul_bones(prvm_prog_t *prog)
4750 {
4751         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4752         int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
4753         int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
4754         int bonenum;
4755         vec3_t forward, left, up, origin;
4756         skeleton_t *skeleton;
4757         matrix4x4_t matrix;
4758         matrix4x4_t temp;
4759         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4760                 return;
4761         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
4762         VectorCopy(PRVM_clientglobalvector(v_forward), forward);
4763         VectorNegate(PRVM_clientglobalvector(v_right), left);
4764         VectorCopy(PRVM_clientglobalvector(v_up), up);
4765         Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
4766         firstbone = max(0, firstbone);
4767         lastbone = min(lastbone, skeleton->model->num_bones - 1);
4768         for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
4769         {
4770                 temp = skeleton->relativetransforms[bonenum];
4771                 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
4772         }
4773 }
4774
4775 // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
4776 static void VM_CL_skel_copybones(prvm_prog_t *prog)
4777 {
4778         int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4779         int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4780         int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
4781         int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
4782         int bonenum;
4783         skeleton_t *skeletondst;
4784         skeleton_t *skeletonsrc;
4785         if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
4786                 return;
4787         if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
4788                 return;
4789         firstbone = max(0, firstbone);
4790         lastbone = min(lastbone, skeletondst->model->num_bones - 1);
4791         lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
4792         for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
4793                 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
4794 }
4795
4796 // #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
4797 static void VM_CL_skel_delete(prvm_prog_t *prog)
4798 {
4799         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4800         skeleton_t *skeleton;
4801         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4802                 return;
4803         Mem_Free(skeleton);
4804         prog->skeletons[skeletonindex] = NULL;
4805 }
4806
4807 // #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found
4808 static void VM_CL_frameforname(prvm_prog_t *prog)
4809 {
4810         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
4811         model_t *model = CL_GetModelByIndex(modelindex);
4812         const char *name = PRVM_G_STRING(OFS_PARM1);
4813         int i;
4814         PRVM_G_FLOAT(OFS_RETURN) = -1;
4815         if (!model || !model->animscenes)
4816                 return;
4817         for (i = 0;i < model->numframes;i++)
4818         {
4819                 if (!strcasecmp(model->animscenes[i].name, name))
4820                 {
4821                         PRVM_G_FLOAT(OFS_RETURN) = i;
4822                         break;
4823                 }
4824         }
4825 }
4826
4827 // #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
4828 static void VM_CL_frameduration(prvm_prog_t *prog)
4829 {
4830         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
4831         model_t *model = CL_GetModelByIndex(modelindex);
4832         int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
4833         PRVM_G_FLOAT(OFS_RETURN) = 0;
4834         if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
4835                 return;
4836         if (model->animscenes[framenum].framerate)
4837                 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
4838 }
4839
4840 static void VM_CL_RotateMoves(prvm_prog_t *prog)
4841 {
4842         /*
4843          * Obscure builtin used by GAME_XONOTIC.
4844          *
4845          * Edits the input history of cl_movement by rotating all move commands
4846          * currently in the queue using the given transform.
4847          *
4848          * The vector passed is an "angles transform" as used by warpzonelib, i.e.
4849          * v_angle-like (non-inverted) euler angles that perform the rotation
4850          * of the space that is to be done.
4851          *
4852          * This is meant to be used as a fixangle replacement after passing
4853          * through a warpzone/portal: the client is told about the warp transform,
4854          * and calls this function in the same frame as the one on which the
4855          * client's origin got changed by the serverside teleport. Then this code
4856          * transforms the pre-warp input (which matches the empty space behind
4857          * the warp plane) into post-warp input (which matches the target area
4858          * of the warp). Also, at the same time, the client has to use
4859          * R_SetView to adjust VF_CL_VIEWANGLES according to the same transform.
4860          *
4861          * This together allows warpzone motion to be perfectly predicted by
4862          * the client!
4863          *
4864          * Furthermore, for perfect warpzone behaviour, the server side also
4865          * has to detect input the client sent before it received the origin
4866          * update, but after the warp occurred on the server, and has to adjust
4867          * input appropriately.
4868     */
4869         matrix4x4_t m;
4870         vec3_t v = {0, 0, 0};
4871         vec3_t a, x, y, z;
4872         VM_SAFEPARMCOUNT(1, VM_CL_RotateMoves);
4873         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), a);
4874         AngleVectorsFLU(a, x, y, z);
4875         Matrix4x4_FromVectors(&m, x, y, z, v);
4876         CL_RotateMoves(&m);
4877 }
4878
4879 // #358 void(string cubemapname) loadcubemap
4880 static void VM_CL_loadcubemap(prvm_prog_t *prog)
4881 {
4882         const char *name;
4883
4884         VM_SAFEPARMCOUNT(1, VM_CL_loadcubemap);
4885         name = PRVM_G_STRING(OFS_PARM0);
4886         R_GetCubemap(name);
4887 }
4888
4889 #define REFDEFFLAG_TELEPORTED 1
4890 #define REFDEFFLAG_JUMPING 2
4891 #define REFDEFFLAG_DEAD 4
4892 #define REFDEFFLAG_INTERMISSION 8
4893 static void VM_CL_V_CalcRefdef(prvm_prog_t *prog)
4894 {
4895         matrix4x4_t entrendermatrix;
4896         vec3_t clviewangles;
4897         vec3_t clvelocity;
4898         qbool teleported;
4899         qbool clonground;
4900         qbool clcmdjump;
4901         qbool cldead;
4902         float clstatsviewheight;
4903         prvm_edict_t *ent;
4904         int flags;
4905
4906         VM_SAFEPARMCOUNT(2, VM_CL_V_CalcRefdef);
4907         ent = PRVM_G_EDICT(OFS_PARM0);
4908         flags = PRVM_G_FLOAT(OFS_PARM1);
4909
4910         // use the CL_GetTagMatrix function on self to ensure consistent behavior (duplicate code would be bad)
4911         CL_GetTagMatrix(prog, &entrendermatrix, ent, 0, NULL);
4912
4913         VectorCopy(cl.csqc_viewangles, clviewangles);
4914         teleported = (flags & REFDEFFLAG_TELEPORTED) != 0;
4915         clonground = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_ONGROUND) != 0;
4916         clcmdjump = (flags & REFDEFFLAG_JUMPING) != 0;
4917         clstatsviewheight = PRVM_clientedictvector(ent, view_ofs)[2];
4918         cldead = (flags & REFDEFFLAG_DEAD) != 0;
4919         cl.intermission = (flags & REFDEFFLAG_INTERMISSION) != 0;
4920         VectorCopy(PRVM_clientedictvector(ent, velocity), clvelocity);
4921
4922         V_CalcRefdefUsing(&entrendermatrix, clviewangles, teleported, clonground, clcmdjump, clstatsviewheight, cldead, clvelocity);
4923
4924         VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
4925         VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
4926         CSQC_R_RecalcView();
4927 }
4928
4929 //============================================================================
4930
4931 // To create a almost working builtin file from this replace:
4932 // "^NULL.*" with ""
4933 // "^{.*//.*}:Wh\(.*\)" with "\1"
4934 // "\:" with "//"
4935 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
4936 // "\n\n+" with "\n\n"
4937
4938 prvm_builtin_t vm_cl_builtins[] = {
4939 NULL,                                                   // #0 NULL function (not callable) (QUAKE)
4940 VM_CL_makevectors,                              // #1 void(vector ang) makevectors (QUAKE)
4941 VM_CL_setorigin,                                // #2 void(entity e, vector o) setorigin (QUAKE)
4942 VM_CL_setmodel,                                 // #3 void(entity e, string m) setmodel (QUAKE)
4943 VM_CL_setsize,                                  // #4 void(entity e, vector min, vector max) setsize (QUAKE)
4944 NULL,                                                   // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
4945 VM_break,                                               // #6 void() break (QUAKE)
4946 VM_random,                                              // #7 float() random (QUAKE)
4947 VM_CL_sound,                                    // #8 void(entity e, float chan, string samp, float volume, float atten[, float pitchchange[, float flags]]) sound (QUAKE)
4948 VM_normalize,                                   // #9 vector(vector v) normalize (QUAKE)
4949 VM_error,                                               // #10 void(string e) error (QUAKE)
4950 VM_objerror,                                    // #11 void(string e) objerror (QUAKE)
4951 VM_vlen,                                                // #12 float(vector v) vlen (QUAKE)
4952 VM_vectoyaw,                                    // #13 float(vector v) vectoyaw (QUAKE)
4953 VM_CL_spawn,                                    // #14 entity() spawn (QUAKE)
4954 VM_remove,                                              // #15 void(entity e) remove (QUAKE)
4955 VM_CL_traceline,                                // #16 void(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
4956 NULL,                                                   // #17 entity() checkclient (QUAKE)
4957 VM_find,                                                // #18 entity(entity start, .string fld, string match) find (QUAKE)
4958 VM_precache_sound,                              // #19 void(string s) precache_sound (QUAKE)
4959 VM_CL_precache_model,                   // #20 void(string s) precache_model (QUAKE)
4960 NULL,                                                   // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
4961 VM_CL_findradius,                               // #22 entity(vector org, float rad) findradius (QUAKE)
4962 NULL,                                                   // #23 void(string s, ...) bprint (QUAKE)
4963 NULL,                                                   // #24 void(entity client, string s, ...) sprint (QUAKE)
4964 VM_dprint,                                              // #25 void(string s, ...) dprint (QUAKE)
4965 VM_ftos,                                                // #26 string(float f) ftos (QUAKE)
4966 VM_vtos,                                                // #27 string(vector v) vtos (QUAKE)
4967 VM_coredump,                                    // #28 void() coredump (QUAKE)
4968 VM_traceon,                                             // #29 void() traceon (QUAKE)
4969 VM_traceoff,                                    // #30 void() traceoff (QUAKE)
4970 VM_eprint,                                              // #31 void(entity e) eprint (QUAKE)
4971 VM_CL_walkmove,                                 // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
4972 NULL,                                                   // #33 (QUAKE)
4973 VM_CL_droptofloor,                              // #34 float() droptofloor (QUAKE)
4974 VM_CL_lightstyle,                               // #35 void(float style, string value) lightstyle (QUAKE)
4975 VM_rint,                                                // #36 float(float v) rint (QUAKE)
4976 VM_floor,                                               // #37 float(float v) floor (QUAKE)
4977 VM_ceil,                                                // #38 float(float v) ceil (QUAKE)
4978 NULL,                                                   // #39 (QUAKE)
4979 VM_CL_checkbottom,                              // #40 float(entity e) checkbottom (QUAKE)
4980 VM_CL_pointcontents,                    // #41 float(vector v) pointcontents (QUAKE)
4981 NULL,                                                   // #42 (QUAKE)
4982 VM_fabs,                                                // #43 float(float f) fabs (QUAKE)
4983 NULL,                                                   // #44 vector(entity e, float speed) aim (QUAKE)
4984 VM_cvar,                                                // #45 float(string s) cvar (QUAKE)
4985 VM_localcmd_local,                              // #46 void(string s) localcmd (QUAKE)
4986 VM_nextent,                                             // #47 entity(entity e) nextent (QUAKE)
4987 VM_CL_particle,                                 // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
4988 VM_changeyaw,                                   // #49 void() ChangeYaw (QUAKE)
4989 NULL,                                                   // #50 (QUAKE)
4990 VM_vectoangles,                                 // #51 vector(vector v) vectoangles (QUAKE)
4991 NULL,                                                   // #52 void(float to, float f) WriteByte (QUAKE)
4992 NULL,                                                   // #53 void(float to, float f) WriteChar (QUAKE)
4993 NULL,                                                   // #54 void(float to, float f) WriteShort (QUAKE)
4994 NULL,                                                   // #55 void(float to, float f) WriteLong (QUAKE)
4995 NULL,                                                   // #56 void(float to, float f) WriteCoord (QUAKE)
4996 NULL,                                                   // #57 void(float to, float f) WriteAngle (QUAKE)
4997 NULL,                                                   // #58 void(float to, string s) WriteString (QUAKE)
4998 NULL,                                                   // #59 (QUAKE)
4999 VM_sin,                                                 // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
5000 VM_cos,                                                 // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
5001 VM_sqrt,                                                // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
5002 VM_changepitch,                                 // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
5003 VM_CL_tracetoss,                                // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
5004 VM_etos,                                                // #65 string(entity ent) etos (DP_QC_ETOS)
5005 NULL,                                                   // #66 (QUAKE)
5006 NULL,                                                   // #67 void(float step) movetogoal (QUAKE)
5007 VM_precache_file,                               // #68 string(string s) precache_file (QUAKE)
5008 VM_CL_makestatic,                               // #69 void(entity e) makestatic (QUAKE)
5009 NULL,                                                   // #70 void(string s) changelevel (QUAKE)
5010 NULL,                                                   // #71 (QUAKE)
5011 VM_cvar_set,                                    // #72 void(string var, string val) cvar_set (QUAKE)
5012 NULL,                                                   // #73 void(entity client, strings) centerprint (QUAKE)
5013 VM_CL_ambientsound,                             // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
5014 VM_CL_precache_model,                   // #75 string(string s) precache_model2 (QUAKE)
5015 VM_precache_sound,                              // #76 string(string s) precache_sound2 (QUAKE)
5016 VM_precache_file,                               // #77 string(string s) precache_file2 (QUAKE)
5017 NULL,                                                   // #78 void(entity e) setspawnparms (QUAKE)
5018 NULL,                                                   // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
5019 NULL,                                                   // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
5020 VM_stof,                                                // #81 float(string s) stof (FRIK_FILE)
5021 NULL,                                                   // #82 void(vector where, float set) multicast (QUAKEWORLD)
5022 NULL,                                                   // #83 (QUAKE)
5023 NULL,                                                   // #84 (QUAKE)
5024 NULL,                                                   // #85 (QUAKE)
5025 NULL,                                                   // #86 (QUAKE)
5026 NULL,                                                   // #87 (QUAKE)
5027 NULL,                                                   // #88 (QUAKE)
5028 NULL,                                                   // #89 (QUAKE)
5029 VM_CL_tracebox,                                 // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
5030 VM_randomvec,                                   // #91 vector() randomvec (DP_QC_RANDOMVEC)
5031 VM_CL_getlight,                                 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
5032 VM_registercvar,                                // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
5033 VM_min,                                                 // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
5034 VM_max,                                                 // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
5035 VM_bound,                                               // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
5036 VM_pow,                                                 // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
5037 VM_findfloat,                                   // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
5038 VM_checkextension,                              // #99 float(string s) checkextension (the basis of the extension system)
5039 // FrikaC and Telejano range #100-#199
5040 NULL,                                                   // #100
5041 NULL,                                                   // #101
5042 NULL,                                                   // #102
5043 NULL,                                                   // #103
5044 NULL,                                                   // #104
5045 NULL,                                                   // #105
5046 NULL,                                                   // #106
5047 NULL,                                                   // #107
5048 NULL,                                                   // #108
5049 NULL,                                                   // #109
5050 VM_fopen,                                               // #110 float(string filename, float mode) fopen (FRIK_FILE)
5051 VM_fclose,                                              // #111 void(float fhandle) fclose (FRIK_FILE)
5052 VM_fgets,                                               // #112 string(float fhandle) fgets (FRIK_FILE)
5053 VM_fputs,                                               // #113 void(float fhandle, string s) fputs (FRIK_FILE)
5054 VM_strlen,                                              // #114 float(string s) strlen (FRIK_FILE)
5055 VM_strcat,                                              // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
5056 VM_substring,                                   // #116 string(string s, float start, float length) substring (FRIK_FILE)
5057 VM_stov,                                                // #117 vector(string) stov (FRIK_FILE)
5058 VM_strzone,                                             // #118 string(string s) strzone (FRIK_FILE)
5059 VM_strunzone,                                   // #119 void(string s) strunzone (FRIK_FILE)
5060 NULL,                                                   // #120
5061 NULL,                                                   // #121
5062 NULL,                                                   // #122
5063 NULL,                                                   // #123
5064 NULL,                                                   // #124
5065 NULL,                                                   // #125
5066 NULL,                                                   // #126
5067 NULL,                                                   // #127
5068 NULL,                                                   // #128
5069 NULL,                                                   // #129
5070 NULL,                                                   // #130
5071 NULL,                                                   // #131
5072 NULL,                                                   // #132
5073 NULL,                                                   // #133
5074 NULL,                                                   // #134
5075 NULL,                                                   // #135
5076 NULL,                                                   // #136
5077 NULL,                                                   // #137
5078 NULL,                                                   // #138
5079 NULL,                                                   // #139
5080 NULL,                                                   // #140
5081 NULL,                                                   // #141
5082 NULL,                                                   // #142
5083 NULL,                                                   // #143
5084 NULL,                                                   // #144
5085 NULL,                                                   // #145
5086 NULL,                                                   // #146
5087 NULL,                                                   // #147
5088 NULL,                                                   // #148
5089 NULL,                                                   // #149
5090 NULL,                                                   // #150
5091 NULL,                                                   // #151
5092 NULL,                                                   // #152
5093 NULL,                                                   // #153
5094 NULL,                                                   // #154
5095 NULL,                                                   // #155
5096 NULL,                                                   // #156
5097 NULL,                                                   // #157
5098 NULL,                                                   // #158
5099 NULL,                                                   // #159
5100 NULL,                                                   // #160
5101 NULL,                                                   // #161
5102 NULL,                                                   // #162
5103 NULL,                                                   // #163
5104 NULL,                                                   // #164
5105 NULL,                                                   // #165
5106 NULL,                                                   // #166
5107 NULL,                                                   // #167
5108 NULL,                                                   // #168
5109 NULL,                                                   // #169
5110 NULL,                                                   // #170
5111 NULL,                                                   // #171
5112 NULL,                                                   // #172
5113 NULL,                                                   // #173
5114 NULL,                                                   // #174
5115 NULL,                                                   // #175
5116 NULL,                                                   // #176
5117 NULL,                                                   // #177
5118 NULL,                                                   // #178
5119 NULL,                                                   // #179
5120 NULL,                                                   // #180
5121 NULL,                                                   // #181
5122 NULL,                                                   // #182
5123 NULL,                                                   // #183
5124 NULL,                                                   // #184
5125 NULL,                                                   // #185
5126 NULL,                                                   // #186
5127 NULL,                                                   // #187
5128 NULL,                                                   // #188
5129 NULL,                                                   // #189
5130 NULL,                                                   // #190
5131 NULL,                                                   // #191
5132 NULL,                                                   // #192
5133 NULL,                                                   // #193
5134 NULL,                                                   // #194
5135 NULL,                                                   // #195
5136 NULL,                                                   // #196
5137 NULL,                                                   // #197
5138 NULL,                                                   // #198
5139 NULL,                                                   // #199
5140 // FTEQW range #200-#299
5141 NULL,                                                   // #200
5142 NULL,                                                   // #201
5143 NULL,                                                   // #202
5144 NULL,                                                   // #203
5145 NULL,                                                   // #204
5146 NULL,                                                   // #205
5147 NULL,                                                   // #206
5148 NULL,                                                   // #207
5149 NULL,                                                   // #208
5150 NULL,                                                   // #209
5151 NULL,                                                   // #210
5152 NULL,                                                   // #211
5153 NULL,                                                   // #212
5154 NULL,                                                   // #213
5155 NULL,                                                   // #214
5156 NULL,                                                   // #215
5157 NULL,                                                   // #216
5158 NULL,                                                   // #217
5159 VM_bitshift,                                    // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
5160 NULL,                                                   // #219
5161 NULL,                                                   // #220
5162 VM_strstrofs,                                   // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
5163 VM_str2chr,                                             // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
5164 VM_chr2str,                                             // #223 string(float c, ...) chr2str (FTE_STRINGS)
5165 VM_strconv,                                             // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
5166 VM_strpad,                                              // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
5167 VM_infoadd,                                             // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
5168 VM_infoget,                                             // #227 string(string info, string key) infoget (FTE_STRINGS)
5169 VM_strncmp,                                             // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
5170 VM_strncasecmp,                                 // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
5171 VM_strncasecmp,                                 // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
5172 NULL,                                                   // #231
5173 NULL,                                                   // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
5174 NULL,                                                   // #233
5175 NULL,                                                   // #234
5176 NULL,                                                   // #235
5177 NULL,                                                   // #236
5178 NULL,                                                   // #237
5179 NULL,                                                   // #238
5180 NULL,                                                   // #239
5181 VM_CL_checkpvs,                                 // #240
5182 NULL,                                                   // #241
5183 NULL,                                                   // #242
5184 NULL,                                                   // #243
5185 NULL,                                                   // #244
5186 VM_modulo,                                              // #245
5187 NULL,                                                   // #246
5188 NULL,                                                   // #247
5189 NULL,                                                   // #248
5190 NULL,                                                   // #249
5191 NULL,                                                   // #250
5192 NULL,                                                   // #251
5193 NULL,                                                   // #252
5194 NULL,                                                   // #253
5195 NULL,                                                   // #254
5196 NULL,                                                   // #255
5197 NULL,                                                   // #256
5198 NULL,                                                   // #257
5199 NULL,                                                   // #258
5200 NULL,                                                   // #259
5201 NULL,                                                   // #260
5202 NULL,                                                   // #261
5203 NULL,                                                   // #262
5204 VM_CL_skel_create,                              // #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure  (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex.
5205 VM_CL_skel_build,                               // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
5206 VM_CL_skel_get_numbones,                // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
5207 VM_CL_skel_get_bonename,                // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
5208 VM_CL_skel_get_boneparent,              // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, -1 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
5209 VM_CL_skel_find_bone,                   // #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
5210 VM_CL_skel_get_bonerel,                 // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
5211 VM_CL_skel_get_boneabs,                 // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
5212 VM_CL_skel_set_bone,                    // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
5213 VM_CL_skel_mul_bone,                    // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
5214 VM_CL_skel_mul_bones,                   // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
5215 VM_CL_skel_copybones,                   // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
5216 VM_CL_skel_delete,                              // #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
5217 VM_CL_frameforname,                             // #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found
5218 VM_CL_frameduration,                    // #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
5219 NULL,                                                   // #278
5220 NULL,                                                   // #279
5221 NULL,                                                   // #280
5222 NULL,                                                   // #281
5223 NULL,                                                   // #282
5224 NULL,                                                   // #283
5225 NULL,                                                   // #284
5226 NULL,                                                   // #285
5227 NULL,                                                   // #286
5228 NULL,                                                   // #287
5229 NULL,                                                   // #288
5230 NULL,                                                   // #289
5231 NULL,                                                   // #290
5232 NULL,                                                   // #291
5233 NULL,                                                   // #292
5234 NULL,                                                   // #293
5235 NULL,                                                   // #294
5236 NULL,                                                   // #295
5237 NULL,                                                   // #296
5238 NULL,                                                   // #297
5239 NULL,                                                   // #298
5240 NULL,                                                   // #299
5241 // CSQC range #300-#399
5242 VM_CL_R_ClearScene,                             // #300 void() clearscene (EXT_CSQC)
5243 VM_CL_R_AddEntities,                    // #301 void(float mask) addentities (EXT_CSQC)
5244 VM_CL_R_AddEntity,                              // #302 void(entity ent) addentity (EXT_CSQC)
5245 VM_CL_R_SetView,                                // #303 float(float property, ...) setproperty (EXT_CSQC)
5246 VM_CL_R_RenderScene,                    // #304 void() renderscene (EXT_CSQC)
5247 VM_CL_R_AddDynamicLight,                // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
5248 VM_CL_R_PolygonBegin,                   // #306 void(string texturename, float flag, float is2d[NYI: , float lines]) R_BeginPolygon
5249 VM_CL_R_PolygonVertex,                  // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
5250 VM_CL_R_PolygonEnd,                             // #308 void() R_EndPolygon
5251 VM_CL_R_SetView,                                // #309 float(float property) getproperty (EXT_CSQC)
5252 VM_CL_unproject,                                // #310 vector (vector v) cs_unproject (EXT_CSQC)
5253 VM_CL_project,                                  // #311 vector (vector v) cs_project (EXT_CSQC)
5254 NULL,                                                   // #312
5255 NULL,                                                   // #313
5256 NULL,                                                   // #314
5257 VM_drawline,                                    // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
5258 VM_iscachedpic,                                 // #316 float(string name) iscachedpic (EXT_CSQC)
5259 VM_precache_pic,                                // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
5260 VM_getimagesize,                                // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
5261 VM_freepic,                                             // #319 void(string name) freepic (EXT_CSQC)
5262 VM_drawcharacter,                               // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
5263 VM_drawstring,                                  // #321 float(vector position, string text, vector scale, vector rgb, float alpha[, float flag]) drawstring (EXT_CSQC, DP_CSQC)
5264 VM_drawpic,                                             // #322 float(vector position, string pic, vector size, vector rgb, float alpha[, float flag]) drawpic (EXT_CSQC)
5265 VM_drawfill,                                    // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
5266 VM_drawsetcliparea,                             // #324 void(float x, float y, float width, float height) drawsetcliparea
5267 VM_drawresetcliparea,                   // #325 void(void) drawresetcliparea
5268 VM_drawcolorcodedstring,                // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
5269 VM_stringwidth,                                 // #327 // FIXME is this okay?
5270 VM_drawsubpic,                                  // #328 // FIXME is this okay?
5271 VM_drawrotpic,                                  // #329 // FIXME is this okay?
5272 VM_CL_getstatf,                                 // #330 float(float stnum) getstatf (EXT_CSQC)
5273 VM_CL_getstati,                                 // #331 float(float stnum) getstati (EXT_CSQC)
5274 VM_CL_getstats,                                 // #332 string(float firststnum) getstats (EXT_CSQC)
5275 VM_CL_setmodelindex,                    // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
5276 VM_CL_modelnameforindex,                // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
5277 VM_CL_particleeffectnum,                // #335 float(string effectname) particleeffectnum (EXT_CSQC)
5278 VM_CL_trailparticles,                   // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
5279 VM_CL_pointparticles,                   // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
5280 VM_centerprint,                                 // #338 void(string s, ...) centerprint (EXT_CSQC)
5281 VM_print,                                               // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
5282 VM_keynumtostring,                              // #340 string(float keynum) keynumtostring (EXT_CSQC)
5283 VM_stringtokeynum,                              // #341 float(string keyname) stringtokeynum (EXT_CSQC)
5284 VM_getkeybind,                                  // #342 string(float keynum[, float bindmap]) getkeybind (EXT_CSQC)
5285 VM_CL_setcursormode,                    // #343 void(float usecursor) setcursormode (DP_CSQC)
5286 VM_CL_getmousepos,                              // #344 vector() getmousepos (DP_CSQC)
5287 VM_CL_getinputstate,                    // #345 float(float framenum) getinputstate (EXT_CSQC)
5288 VM_CL_setsensitivityscale,              // #346 void(float sens) setsensitivityscale (EXT_CSQC)
5289 VM_CL_runplayerphysics,                 // #347 void() runstandardplayerphysics (EXT_CSQC)
5290 VM_CL_getplayerkey,                             // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
5291 VM_CL_isdemo,                                   // #349 float() isdemo (EXT_CSQC)
5292 VM_isserver,                                    // #350 float() isserver (EXT_CSQC)
5293 VM_CL_setlistener,                              // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
5294 VM_CL_registercmd,                              // #352 void(string cmdname) registercommand (EXT_CSQC)
5295 VM_wasfreed,                                    // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
5296 VM_CL_serverkey,                                // #354 string(string key) serverkey (EXT_CSQC)
5297 VM_CL_videoplaying,                             // #355
5298 VM_findfont,                                    // #356 float(string fontname) loadfont (DP_GFX_FONTS)
5299 VM_loadfont,                                    // #357 float(string fontname, string fontmaps, string sizes, float slot) loadfont (DP_GFX_FONTS)
5300 VM_CL_loadcubemap,                              // #358 void(string cubemapname) loadcubemap (DP_GFX_)
5301 NULL,                                                   // #359
5302 VM_CL_ReadByte,                                 // #360 float() readbyte (EXT_CSQC)
5303 VM_CL_ReadChar,                                 // #361 float() readchar (EXT_CSQC)
5304 VM_CL_ReadShort,                                // #362 float() readshort (EXT_CSQC)
5305 VM_CL_ReadLong,                                 // #363 float() readlong (EXT_CSQC)
5306 VM_CL_ReadCoord,                                // #364 float() readcoord (EXT_CSQC)
5307 VM_CL_ReadAngle,                                // #365 float() readangle (EXT_CSQC)
5308 VM_CL_ReadString,                               // #366 string() readstring (EXT_CSQC)
5309 VM_CL_ReadFloat,                                // #367 float() readfloat (EXT_CSQC)
5310 NULL,                                           // #368
5311 NULL,                                                   // #369
5312 NULL,                                                   // #370
5313 NULL,                                                   // #371
5314 NULL,                                                   // #372
5315 NULL,                                                   // #373
5316 NULL,                                                   // #374
5317 NULL,                                                   // #375
5318 NULL,                                                   // #376
5319 NULL,                                                   // #377
5320 NULL,                                                   // #378
5321 NULL,                                                   // #379
5322 NULL,                                                   // #380
5323 NULL,                                                   // #381
5324 NULL,                                                   // #382
5325 NULL,                                                   // #383
5326 NULL,                                                   // #384
5327 NULL,                                                   // #385
5328 NULL,                                                   // #386
5329 NULL,                                                   // #387
5330 NULL,                                                   // #388
5331 NULL,                                                   // #389
5332 NULL,                                                   // #390
5333 NULL,                                                   // #391
5334 NULL,                                                   // #392
5335 NULL,                                                   // #393
5336 NULL,                                                   // #394
5337 NULL,                                                   // #395
5338 NULL,                                                   // #396
5339 NULL,                                                   // #397
5340 NULL,                                                   // #398
5341 NULL,                                                   // #399
5342 // LadyHavoc's range #400-#499
5343 VM_CL_copyentity,                               // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
5344 NULL,                                                   // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
5345 VM_findchain,                                   // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
5346 VM_findchainfloat,                              // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
5347 VM_CL_effect,                                   // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
5348 VM_CL_te_blood,                                 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
5349 VM_CL_te_bloodshower,                   // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
5350 VM_CL_te_explosionrgb,                  // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
5351 VM_CL_te_particlecube,                  // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
5352 VM_CL_te_particlerain,                  // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
5353 VM_CL_te_particlesnow,                  // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
5354 VM_CL_te_spark,                                 // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
5355 VM_CL_te_gunshotquad,                   // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
5356 VM_CL_te_spikequad,                             // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
5357 VM_CL_te_superspikequad,                // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
5358 VM_CL_te_explosionquad,                 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
5359 VM_CL_te_smallflash,                    // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
5360 VM_CL_te_customflash,                   // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
5361 VM_CL_te_gunshot,                               // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
5362 VM_CL_te_spike,                                 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
5363 VM_CL_te_superspike,                    // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
5364 VM_CL_te_explosion,                             // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
5365 VM_CL_te_tarexplosion,                  // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
5366 VM_CL_te_wizspike,                              // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
5367 VM_CL_te_knightspike,                   // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
5368 VM_CL_te_lavasplash,                    // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
5369 VM_CL_te_teleport,                              // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
5370 VM_CL_te_explosion2,                    // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
5371 VM_CL_te_lightning1,                    // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
5372 VM_CL_te_lightning2,                    // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
5373 VM_CL_te_lightning3,                    // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
5374 VM_CL_te_beam,                                  // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
5375 VM_vectorvectors,                               // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
5376 VM_CL_te_plasmaburn,                    // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
5377 VM_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
5378 VM_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
5379 VM_getsurfacenormal,                    // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
5380 VM_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
5381 VM_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
5382 VM_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
5383 NULL,                                                   // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
5384 VM_tokenize,                                    // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
5385 VM_argv,                                                // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
5386 VM_CL_setattachment,                    // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
5387 VM_search_begin,                                // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
5388 VM_search_end,                                  // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
5389 VM_search_getsize,                              // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
5390 VM_search_getfilename,                  // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
5391 VM_cvar_string,                                 // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
5392 VM_findflags,                                   // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
5393 VM_findchainflags,                              // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
5394 VM_CL_gettagindex,                              // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
5395 VM_CL_gettaginfo,                               // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
5396 NULL,                                                   // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
5397 NULL,                                                   // #454 entity() spawnclient (DP_SV_BOTCLIENT)
5398 NULL,                                                   // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
5399 NULL,                                                   // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
5400 VM_CL_te_flamejet,                              // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
5401 NULL,                                                   // #458
5402 VM_ftoe,                                                // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
5403 VM_buf_create,                                  // #460 float() buf_create (DP_QC_STRINGBUFFERS)
5404 VM_buf_del,                                             // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
5405 VM_buf_getsize,                                 // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
5406 VM_buf_copy,                                    // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
5407 VM_buf_sort,                                    // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
5408 VM_buf_implode,                                 // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
5409 VM_bufstr_get,                                  // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
5410 VM_bufstr_set,                                  // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
5411 VM_bufstr_add,                                  // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
5412 VM_bufstr_free,                                 // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
5413 NULL,                                                   // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
5414 VM_asin,                                                // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
5415 VM_acos,                                                // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
5416 VM_atan,                                                // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
5417 VM_atan2,                                               // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
5418 VM_tan,                                                 // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
5419 VM_strlennocol,                                 // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
5420 VM_strdecolorize,                               // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
5421 VM_strftime,                                    // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
5422 VM_tokenizebyseparator,                 // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
5423 VM_strtolower,                                  // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
5424 VM_strtoupper,                                  // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
5425 VM_cvar_defstring,                              // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
5426 VM_CL_pointsound,                               // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
5427 VM_strreplace,                                  // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
5428 VM_strireplace,                                 // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
5429 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
5430 VM_gecko_create,                                        // #487 float gecko_create( string name )
5431 VM_gecko_destroy,                                       // #488 void gecko_destroy( string name )
5432 VM_gecko_navigate,                              // #489 void gecko_navigate( string name, string URI )
5433 VM_gecko_keyevent,                              // #490 float gecko_keyevent( string name, float key, float eventtype )
5434 VM_gecko_movemouse,                             // #491 void gecko_mousemove( string name, float x, float y )
5435 VM_gecko_resize,                                        // #492 void gecko_resize( string name, float w, float h )
5436 VM_gecko_get_texture_extent,    // #493 vector gecko_get_texture_extent( string name )
5437 VM_crc16,                                               // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
5438 VM_cvar_type,                                   // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
5439 VM_numentityfields,                             // #496 float() numentityfields = #496; (QP_QC_ENTITYDATA)
5440 VM_entityfieldname,                             // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
5441 VM_entityfieldtype,                             // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
5442 VM_getentityfieldstring,                // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
5443 VM_putentityfieldstring,                // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
5444 VM_CL_ReadPicture,                              // #501 string() ReadPicture = #501;
5445 VM_CL_boxparticles,                             // #502 void(float effectnum, entity own, vector origin_from, vector origin_to, vector dir_from, vector dir_to, float count) boxparticles (DP_CSQC_BOXPARTICLES)
5446 VM_whichpack,                                   // #503 string(string) whichpack = #503;
5447 VM_CL_GetEntity,                                // #504 float(float entitynum, float fldnum) getentity = #504; vector(float entitynum, float fldnum) getentityvec = #504;
5448 NULL,                                                   // #505
5449 NULL,                                                   // #506
5450 NULL,                                                   // #507
5451 NULL,                                                   // #508
5452 NULL,                                                   // #509
5453 VM_uri_escape,                                  // #510 string(string in) uri_escape = #510;
5454 VM_uri_unescape,                                // #511 string(string in) uri_unescape = #511;
5455 VM_etof,                                        // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
5456 VM_uri_get,                                             // #513 float(string uri, float id, [string post_contenttype, string post_delim, [float buf]]) uri_get = #513; (DP_QC_URI_GET, DP_QC_URI_POST)
5457 VM_tokenize_console,                                    // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
5458 VM_argv_start_index,                                    // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
5459 VM_argv_end_index,                                              // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
5460 VM_buf_cvarlist,                                                // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
5461 VM_cvar_description,                                    // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
5462 VM_gettime,                                             // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
5463 VM_keynumtostring,                              // #520 string keynumtostring(float keynum)
5464 VM_findkeysforcommand,                  // #521 string findkeysforcommand(string command[, float bindmap])
5465 VM_CL_InitParticleSpawner,              // #522 void(float max_themes) initparticlespawner (DP_CSQC_SPAWNPARTICLE)
5466 VM_CL_ResetParticle,                    // #523 void() resetparticle (DP_CSQC_SPAWNPARTICLE)
5467 VM_CL_ParticleTheme,                    // #524 void(float theme) particletheme (DP_CSQC_SPAWNPARTICLE)
5468 VM_CL_ParticleThemeSave,                // #525 void() particlethemesave, void(float theme) particlethemeupdate (DP_CSQC_SPAWNPARTICLE)
5469 VM_CL_ParticleThemeFree,                // #526 void() particlethemefree (DP_CSQC_SPAWNPARTICLE)
5470 VM_CL_SpawnParticle,                    // #527 float(vector org, vector vel, [float theme]) particle (DP_CSQC_SPAWNPARTICLE)
5471 VM_CL_SpawnParticleDelayed,             // #528 float(vector org, vector vel, float delay, float collisiondelay, [float theme]) delayedparticle (DP_CSQC_SPAWNPARTICLE)
5472 VM_loadfromdata,                                // #529
5473 VM_loadfromfile,                                // #530
5474 VM_CL_setpause,                                 // #531 float(float ispaused) setpause = #531 (DP_CSQC_SETPAUSE)
5475 VM_log,                                                 // #532
5476 VM_getsoundtime,                                // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
5477 VM_soundlength,                                 // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
5478 VM_buf_loadfile,                // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
5479 VM_buf_writefile,               // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
5480 VM_bufstr_find,                 // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
5481 VM_matchpattern,                // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
5482 NULL,                                                   // #539
5483 VM_physics_enable,                              // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
5484 VM_physics_addforce,                    // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
5485 VM_physics_addtorque,                   // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
5486 NULL,                                                   // #543
5487 NULL,                                                   // #544
5488 NULL,                                                   // #545
5489 NULL,                                                   // #546
5490 NULL,                                                   // #547
5491 NULL,                                                   // #548
5492 NULL,                                                   // #549
5493 NULL,                                                   // #550
5494 NULL,                                                   // #551
5495 NULL,                                                   // #552
5496 NULL,                                                   // #553
5497 NULL,                                                   // #554
5498 NULL,                                                   // #555
5499 NULL,                                                   // #556
5500 NULL,                                                   // #557
5501 NULL,                                                   // #558
5502 NULL,                                                   // #559
5503 NULL,                                                   // #560
5504 NULL,                                                   // #561
5505 NULL,                                                   // #562
5506 NULL,                                                   // #563
5507 NULL,                                                   // #564
5508 NULL,                                                   // #565
5509 NULL,                                                   // #566
5510 NULL,                                                   // #567
5511 NULL,                                                   // #568
5512 NULL,                                                   // #569
5513 NULL,                                                   // #570
5514 NULL,                                                   // #571
5515 NULL,                                                   // #572
5516 NULL,                                                   // #573
5517 NULL,                                                   // #574
5518 NULL,                                                   // #575
5519 NULL,                                                   // #576
5520 NULL,                                                   // #577
5521 NULL,                                                   // #578
5522 NULL,                                                   // #579
5523 NULL,                                                   // #580
5524 NULL,                                                   // #581
5525 NULL,                                                   // #582
5526 NULL,                                                   // #583
5527 NULL,                                                   // #584
5528 NULL,                                                   // #585
5529 NULL,                                                   // #586
5530 NULL,                                                   // #587
5531 NULL,                                                   // #588
5532 NULL,                                                   // #589
5533 NULL,                                                   // #590
5534 NULL,                                                   // #591
5535 NULL,                                                   // #592
5536 NULL,                                                   // #593
5537 NULL,                                                   // #594
5538 NULL,                                                   // #595
5539 NULL,                                                   // #596
5540 NULL,                                                   // #597
5541 NULL,                                                   // #598
5542 NULL,                                                   // #599
5543 NULL,                                                   // #600
5544 NULL,                                                   // #601
5545 NULL,                                                   // #602
5546 NULL,                                                   // #603
5547 NULL,                                                   // #604
5548 VM_callfunction,                                // #605
5549 VM_writetofile,                                 // #606
5550 VM_isfunction,                                  // #607
5551 NULL,                                                   // #608
5552 NULL,                                                   // #609
5553 VM_findkeysforcommand,                  // #610 string findkeysforcommand(string command[, float bindmap])
5554 NULL,                                                   // #611
5555 NULL,                                                   // #612
5556 VM_parseentitydata,                             // #613
5557 NULL,                                                   // #614
5558 NULL,                                                   // #615
5559 NULL,                                                   // #616
5560 NULL,                                                   // #617
5561 NULL,                                                   // #618
5562 NULL,                                                   // #619
5563 NULL,                                                   // #620
5564 NULL,                                                   // #621
5565 NULL,                                                   // #622
5566 NULL,                                                   // #623
5567 VM_CL_getextresponse,                   // #624 string getextresponse(void)
5568 NULL,                                                   // #625
5569 NULL,                                                   // #626
5570 VM_sprintf,                     // #627 string sprintf(string format, ...)
5571 VM_getsurfacenumtriangles,              // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
5572 VM_getsurfacetriangle,                  // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
5573 VM_setkeybind,                                          // #630 float(float key, string bind[, float bindmap]) setkeybind
5574 VM_getbindmaps,                                         // #631 vector(void) getbindmap
5575 VM_setbindmaps,                                         // #632 float(vector bm) setbindmap
5576 NULL,                                                   // #633
5577 NULL,                                                   // #634
5578 NULL,                                                   // #635
5579 NULL,                                                   // #636
5580 NULL,                                                   // #637
5581 VM_CL_RotateMoves,                                      // #638
5582 VM_digest_hex,                                          // #639
5583 VM_CL_V_CalcRefdef,                                     // #640 void(entity e) V_CalcRefdef (DP_CSQC_V_CALCREFDEF)
5584 NULL,                                                   // #641
5585 VM_coverage,                                            // #642
5586 NULL
5587 };
5588
5589 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
5590
5591 void CLVM_init_cmd(prvm_prog_t *prog)
5592 {
5593         VM_Cmd_Init(prog);
5594         prog->polygonbegin_model = NULL;
5595         prog->polygonbegin_guess2d = 0;
5596 }
5597
5598 void CLVM_reset_cmd(prvm_prog_t *prog)
5599 {
5600         World_End(&cl.world);
5601         VM_Cmd_Reset(prog);
5602         prog->polygonbegin_model = NULL;
5603         prog->polygonbegin_guess2d = 0;
5604 }