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