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