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