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