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