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