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