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