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