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