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