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