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