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