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