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