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