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