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