]> icculus.org git repositories - divverent/darkplaces.git/blob - clvm_cmds.c
+"DP_QC_CVAR_DESCRIPTION "
[divverent/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
25 sfx_t *S_FindName(const char *name);
26 int Sbar_GetSortedPlayerIndex (int index);
27 void Sbar_SortFrags (void);
28 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
29 void CSQC_RelinkAllEntities (int drawmask);
30 void CSQC_RelinkCSQCEntities (void);
31 const char *Key_GetBind (int key);
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), prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->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, e->fields.client->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, e->fields.client->mins);
73         VectorCopy (max, e->fields.client->maxs);
74         VectorSubtract (max, min, e->fields.client->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         e->fields.client->modelindex = 0;
91         e->fields.client->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                         e->fields.client->model = PRVM_SetEngineString(mod->name);
101                         e->fields.client->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                                 e->fields.client->model = PRVM_SetEngineString(mod->name);
113                                 e->fields.client->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
165         VM_SAFEPARMCOUNT(5, VM_CL_sound);
166
167         entity = PRVM_G_EDICT(OFS_PARM0);
168         channel = (int)PRVM_G_FLOAT(OFS_PARM1);
169         sample = PRVM_G_STRING(OFS_PARM2);
170         volume = PRVM_G_FLOAT(OFS_PARM3);
171         attenuation = PRVM_G_FLOAT(OFS_PARM4);
172
173         if (volume < 0 || volume > 1)
174         {
175                 VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
176                 return;
177         }
178
179         if (attenuation < 0 || attenuation > 4)
180         {
181                 VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
182                 return;
183         }
184
185         if (channel < 0 || channel > 7)
186         {
187                 VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
188                 return;
189         }
190
191         S_StartSound(32768 + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), entity->fields.client->origin, volume, attenuation);
192 }
193
194 // #483 void(vector origin, string sample, float volume, float attenuation) pointsound
195 static void VM_CL_pointsound(void)
196 {
197         const char                      *sample;
198         float                           volume;
199         float                           attenuation;
200         vec3_t                          org;
201
202         VM_SAFEPARMCOUNT(4, VM_CL_pointsound);
203
204         VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org);
205         sample = PRVM_G_STRING(OFS_PARM1);
206         volume = PRVM_G_FLOAT(OFS_PARM2);
207         attenuation = PRVM_G_FLOAT(OFS_PARM3);
208
209         if (volume < 0 || volume > 1)
210         {
211                 VM_Warning("VM_CL_pointsound: volume must be in range 0-1\n");
212                 return;
213         }
214
215         if (attenuation < 0 || attenuation > 4)
216         {
217                 VM_Warning("VM_CL_pointsound: attenuation must be in range 0-4\n");
218                 return;
219         }
220
221         // Send World Entity as Entity to Play Sound (for CSQC, that is 32768)
222         S_StartSound(32768, 0, S_FindName(sample), org, volume, attenuation);
223 }
224
225 // #14 entity() spawn
226 static void VM_CL_spawn (void)
227 {
228         prvm_edict_t *ed;
229         ed = PRVM_ED_Alloc();
230         VM_RETURN_EDICT(ed);
231 }
232
233 void CL_VM_SetTraceGlobals(const trace_t *trace, int svent)
234 {
235         prvm_eval_t *val;
236         VM_SetTraceGlobals(trace);
237         if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_networkentity)))
238                 val->_float = svent;
239 }
240
241 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
242 static void VM_CL_traceline (void)
243 {
244         float   *v1, *v2;
245         trace_t trace;
246         int             move, svent;
247         prvm_edict_t    *ent;
248
249         VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
250
251         prog->xfunction->builtinsprofile += 30;
252
253         v1 = PRVM_G_VECTOR(OFS_PARM0);
254         v2 = PRVM_G_VECTOR(OFS_PARM1);
255         move = (int)PRVM_G_FLOAT(OFS_PARM2);
256         ent = PRVM_G_EDICT(OFS_PARM3);
257
258         if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
259                 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));
260
261         trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
262
263         CL_VM_SetTraceGlobals(&trace, svent);
264 }
265
266 /*
267 =================
268 VM_CL_tracebox
269
270 Used for use tracing and shot targeting
271 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
272 if the tryents flag is set.
273
274 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
275 =================
276 */
277 // LordHavoc: added this for my own use, VERY useful, similar to traceline
278 static void VM_CL_tracebox (void)
279 {
280         float   *v1, *v2, *m1, *m2;
281         trace_t trace;
282         int             move, svent;
283         prvm_edict_t    *ent;
284
285         VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
286
287         prog->xfunction->builtinsprofile += 30;
288
289         v1 = PRVM_G_VECTOR(OFS_PARM0);
290         m1 = PRVM_G_VECTOR(OFS_PARM1);
291         m2 = PRVM_G_VECTOR(OFS_PARM2);
292         v2 = PRVM_G_VECTOR(OFS_PARM3);
293         move = (int)PRVM_G_FLOAT(OFS_PARM4);
294         ent = PRVM_G_EDICT(OFS_PARM5);
295
296         if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
297                 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));
298
299         trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
300
301         CL_VM_SetTraceGlobals(&trace, svent);
302 }
303
304 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
305 {
306         int i;
307         float gravity;
308         vec3_t move, end;
309         vec3_t original_origin;
310         vec3_t original_velocity;
311         vec3_t original_angles;
312         vec3_t original_avelocity;
313         prvm_eval_t *val;
314         trace_t trace;
315
316         VectorCopy(tossent->fields.client->origin   , original_origin   );
317         VectorCopy(tossent->fields.client->velocity , original_velocity );
318         VectorCopy(tossent->fields.client->angles   , original_angles   );
319         VectorCopy(tossent->fields.client->avelocity, original_avelocity);
320
321         val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
322         if (val != NULL && val->_float != 0)
323                 gravity = val->_float;
324         else
325                 gravity = 1.0;
326         gravity *= cl.movevars_gravity * 0.05;
327
328         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
329         {
330                 tossent->fields.client->velocity[2] -= gravity;
331                 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
332                 VectorScale (tossent->fields.client->velocity, 0.05, move);
333                 VectorAdd (tossent->fields.client->origin, move, end);
334                 trace = CL_Move (tossent->fields.client->origin, tossent->fields.client->mins, tossent->fields.client->maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
335                 VectorCopy (trace.endpos, tossent->fields.client->origin);
336
337                 if (trace.fraction < 1)
338                         break;
339         }
340
341         VectorCopy(original_origin   , tossent->fields.client->origin   );
342         VectorCopy(original_velocity , tossent->fields.client->velocity );
343         VectorCopy(original_angles   , tossent->fields.client->angles   );
344         VectorCopy(original_avelocity, tossent->fields.client->avelocity);
345
346         return trace;
347 }
348
349 static void VM_CL_tracetoss (void)
350 {
351         trace_t trace;
352         prvm_edict_t    *ent;
353         prvm_edict_t    *ignore;
354         int svent;
355
356         prog->xfunction->builtinsprofile += 600;
357
358         VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
359
360         ent = PRVM_G_EDICT(OFS_PARM0);
361         if (ent == prog->edicts)
362         {
363                 VM_Warning("tracetoss: can not use world entity\n");
364                 return;
365         }
366         ignore = PRVM_G_EDICT(OFS_PARM1);
367
368         trace = CL_Trace_Toss (ent, ignore, &svent);
369
370         CL_VM_SetTraceGlobals(&trace, svent);
371 }
372
373
374 // #20 void(string s) precache_model
375 void VM_CL_precache_model (void)
376 {
377         const char      *name;
378         int                     i;
379         dp_model_t              *m;
380
381         VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
382
383         name = PRVM_G_STRING(OFS_PARM0);
384         for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
385         {
386                 if(!strcmp(cl.csqc_model_precache[i]->name, name))
387                 {
388                         PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
389                         return;
390                 }
391         }
392         PRVM_G_FLOAT(OFS_RETURN) = 0;
393         m = Mod_ForName(name, false, false, false);
394         if(m && m->loaded)
395         {
396                 for (i = 0;i < MAX_MODELS;i++)
397                 {
398                         if (!cl.csqc_model_precache[i])
399                         {
400                                 cl.csqc_model_precache[i] = (dp_model_t*)m;
401                                 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
402                                 return;
403                         }
404                 }
405                 VM_Warning("VM_CL_precache_model: no free models\n");
406                 return;
407         }
408         VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
409 }
410
411 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
412 {
413         prvm_edict_t    *ent;
414         int                             i, k;
415
416         ent = PRVM_NEXT_EDICT(prog->edicts);
417         for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
418         {
419                 if (ent->priv.required->free)
420                         continue;
421                 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
422                         list[k++] = ent;
423         }
424         return k;
425 }
426
427 // #22 entity(vector org, float rad) findradius
428 static void VM_CL_findradius (void)
429 {
430         prvm_edict_t    *ent, *chain;
431         vec_t                   radius, radius2;
432         vec3_t                  org, eorg, mins, maxs;
433         int                             i, numtouchedicts;
434         prvm_edict_t    *touchedicts[MAX_EDICTS];
435
436         VM_SAFEPARMCOUNT(2, VM_CL_findradius);
437
438         chain = (prvm_edict_t *)prog->edicts;
439
440         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
441         radius = PRVM_G_FLOAT(OFS_PARM1);
442         radius2 = radius * radius;
443
444         mins[0] = org[0] - (radius + 1);
445         mins[1] = org[1] - (radius + 1);
446         mins[2] = org[2] - (radius + 1);
447         maxs[0] = org[0] + (radius + 1);
448         maxs[1] = org[1] + (radius + 1);
449         maxs[2] = org[2] + (radius + 1);
450         numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
451         if (numtouchedicts > MAX_EDICTS)
452         {
453                 // this never happens   //[515]: for what then ?
454                 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
455                 numtouchedicts = MAX_EDICTS;
456         }
457         for (i = 0;i < numtouchedicts;i++)
458         {
459                 ent = touchedicts[i];
460                 // Quake did not return non-solid entities but darkplaces does
461                 // (note: this is the reason you can't blow up fallen zombies)
462                 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
463                         continue;
464                 // LordHavoc: compare against bounding box rather than center so it
465                 // doesn't miss large objects, and use DotProduct instead of Length
466                 // for a major speedup
467                 VectorSubtract(org, ent->fields.client->origin, eorg);
468                 if (sv_gameplayfix_findradiusdistancetobox.integer)
469                 {
470                         eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
471                         eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
472                         eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
473                 }
474                 else
475                         VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
476                 if (DotProduct(eorg, eorg) < radius2)
477                 {
478                         ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
479                         chain = ent;
480                 }
481         }
482
483         VM_RETURN_EDICT(chain);
484 }
485
486 // #34 float() droptofloor
487 static void VM_CL_droptofloor (void)
488 {
489         prvm_edict_t            *ent;
490         prvm_eval_t                     *val;
491         vec3_t                          end;
492         trace_t                         trace;
493
494         VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
495
496         // assume failure if it returns early
497         PRVM_G_FLOAT(OFS_RETURN) = 0;
498
499         ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
500         if (ent == prog->edicts)
501         {
502                 VM_Warning("droptofloor: can not modify world entity\n");
503                 return;
504         }
505         if (ent->priv.server->free)
506         {
507                 VM_Warning("droptofloor: can not modify free entity\n");
508                 return;
509         }
510
511         VectorCopy (ent->fields.client->origin, end);
512         end[2] -= 256;
513
514         trace = CL_Move(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
515
516         if (trace.fraction != 1)
517         {
518                 VectorCopy (trace.endpos, ent->fields.client->origin);
519                 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
520                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
521                         val->edict = PRVM_EDICT_TO_PROG(trace.ent);
522                 PRVM_G_FLOAT(OFS_RETURN) = 1;
523                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
524 //              ent->priv.server->suspendedinairflag = true;
525         }
526 }
527
528 // #35 void(float style, string value) lightstyle
529 static void VM_CL_lightstyle (void)
530 {
531         int                     i;
532         const char      *c;
533
534         VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
535
536         i = (int)PRVM_G_FLOAT(OFS_PARM0);
537         c = PRVM_G_STRING(OFS_PARM1);
538         if (i >= cl.max_lightstyle)
539         {
540                 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
541                 return;
542         }
543         strlcpy (cl.lightstyle[i].map,  MSG_ReadString(), sizeof (cl.lightstyle[i].map));
544         cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
545         cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
546 }
547
548 // #40 float(entity e) checkbottom
549 static void VM_CL_checkbottom (void)
550 {
551         static int              cs_yes, cs_no;
552         prvm_edict_t    *ent;
553         vec3_t                  mins, maxs, start, stop;
554         trace_t                 trace;
555         int                             x, y;
556         float                   mid, bottom;
557
558         VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
559         ent = PRVM_G_EDICT(OFS_PARM0);
560         PRVM_G_FLOAT(OFS_RETURN) = 0;
561
562         VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
563         VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
564
565 // if all of the points under the corners are solid world, don't bother
566 // with the tougher checks
567 // the corners must be within 16 of the midpoint
568         start[2] = mins[2] - 1;
569         for     (x=0 ; x<=1 ; x++)
570                 for     (y=0 ; y<=1 ; y++)
571                 {
572                         start[0] = x ? maxs[0] : mins[0];
573                         start[1] = y ? maxs[1] : mins[1];
574                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
575                                 goto realcheck;
576                 }
577
578         cs_yes++;
579         PRVM_G_FLOAT(OFS_RETURN) = true;
580         return;         // we got out easy
581
582 realcheck:
583         cs_no++;
584 //
585 // check it for real...
586 //
587         start[2] = mins[2];
588
589 // the midpoint must be within 16 of the bottom
590         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
591         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
592         stop[2] = start[2] - 2*sv_stepheight.value;
593         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
594
595         if (trace.fraction == 1.0)
596                 return;
597
598         mid = bottom = trace.endpos[2];
599
600 // the corners must be within 16 of the midpoint
601         for     (x=0 ; x<=1 ; x++)
602                 for     (y=0 ; y<=1 ; y++)
603                 {
604                         start[0] = stop[0] = x ? maxs[0] : mins[0];
605                         start[1] = stop[1] = y ? maxs[1] : mins[1];
606
607                         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
608
609                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
610                                 bottom = trace.endpos[2];
611                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
612                                 return;
613                 }
614
615         cs_yes++;
616         PRVM_G_FLOAT(OFS_RETURN) = true;
617 }
618
619 // #41 float(vector v) pointcontents
620 static void VM_CL_pointcontents (void)
621 {
622         VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
623         PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
624 }
625
626 // #48 void(vector o, vector d, float color, float count) particle
627 static void VM_CL_particle (void)
628 {
629         float   *org, *dir;
630         int             count;
631         unsigned char   color;
632         VM_SAFEPARMCOUNT(4, VM_CL_particle);
633
634         org = PRVM_G_VECTOR(OFS_PARM0);
635         dir = PRVM_G_VECTOR(OFS_PARM1);
636         color = (int)PRVM_G_FLOAT(OFS_PARM2);
637         count = (int)PRVM_G_FLOAT(OFS_PARM3);
638         CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
639 }
640
641 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
642 static void VM_CL_ambientsound (void)
643 {
644         float   *f;
645         sfx_t   *s;
646         VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
647         s = S_FindName(PRVM_G_STRING(OFS_PARM0));
648         f = PRVM_G_VECTOR(OFS_PARM1);
649         S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
650 }
651
652 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
653 static void VM_CL_getlight (void)
654 {
655         vec3_t ambientcolor, diffusecolor, diffusenormal;
656         vec_t *p;
657
658         VM_SAFEPARMCOUNT(1, VM_CL_getlight);
659
660         p = PRVM_G_VECTOR(OFS_PARM0);
661         VectorClear(ambientcolor);
662         VectorClear(diffusecolor);
663         VectorClear(diffusenormal);
664         if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
665                 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
666         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
667 }
668
669
670 //============================================================================
671 //[515]: SCENE MANAGER builtins
672 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
673
674 static void CSQC_R_RecalcView (void)
675 {
676         extern matrix4x4_t viewmodelmatrix;
677         Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], 1);
678         Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], cl_viewmodel_scale.value);
679 }
680
681 void CL_RelinkLightFlashes(void);
682 //#300 void() clearscene (EXT_CSQC)
683 void VM_CL_R_ClearScene (void)
684 {
685         VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
686         // clear renderable entity and light lists
687         r_refdef.scene.numentities = 0;
688         r_refdef.scene.numlights = 0;
689         // FIXME: restore these to the values from VM_CL_UpdateView
690         r_refdef.view.x = 0;
691         r_refdef.view.y = 0;
692         r_refdef.view.z = 0;
693         r_refdef.view.width = vid.width;
694         r_refdef.view.height = vid.height;
695         r_refdef.view.depth = 1;
696         // FIXME: restore frustum_x/frustum_y
697         r_refdef.view.useperspective = true;
698         r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
699         r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
700         r_refdef.view.frustum_x *= r_refdef.frustumscale_x;
701         r_refdef.view.frustum_y *= r_refdef.frustumscale_y;
702         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;
703         r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
704         r_refdef.view.clear = true;
705         r_refdef.view.isoverlay = false;
706         // FIXME: restore cl.csqc_origin
707         // FIXME: restore cl.csqc_angles
708         cl.csqc_vidvars.drawworld = true;
709         cl.csqc_vidvars.drawenginesbar = false;
710         cl.csqc_vidvars.drawcrosshair = false;
711 }
712
713 //#301 void(float mask) addentities (EXT_CSQC)
714 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
715 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
716 void VM_CL_R_AddEntities (void)
717 {
718         int                     i, drawmask;
719         prvm_edict_t *ed;
720         VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
721         drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
722         CSQC_RelinkAllEntities(drawmask);
723         CL_RelinkLightFlashes();
724
725         prog->globals.client->time = cl.time;
726         for(i=1;i<prog->num_edicts;i++)
727         {
728                 ed = &prog->edicts[i];
729                 if(ed->priv.required->free)
730                         continue;
731                 CSQC_Think(ed);
732                 if(ed->priv.required->free)
733                         continue;
734                 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
735                 CSQC_Predraw(ed);
736                 if(ed->priv.required->free)
737                         continue;
738                 if(!((int)ed->fields.client->drawmask & drawmask))
739                         continue;
740                 CSQC_AddRenderEdict(ed);
741         }
742 }
743
744 //#302 void(entity ent) addentity (EXT_CSQC)
745 void VM_CL_R_AddEntity (void)
746 {
747         VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
748         CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
749 }
750
751 //#303 float(float property, ...) setproperty (EXT_CSQC)
752 void VM_CL_R_SetView (void)
753 {
754         int             c;
755         float   *f;
756         float   k;
757
758         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
759
760         c = (int)PRVM_G_FLOAT(OFS_PARM0);
761         f = PRVM_G_VECTOR(OFS_PARM1);
762         k = PRVM_G_FLOAT(OFS_PARM1);
763
764         switch(c)
765         {
766         case VF_MIN:
767                 r_refdef.view.x = (int)(f[0]);
768                 r_refdef.view.y = (int)(f[1]);
769                 break;
770         case VF_MIN_X:
771                 r_refdef.view.x = (int)(k);
772                 break;
773         case VF_MIN_Y:
774                 r_refdef.view.y = (int)(k);
775                 break;
776         case VF_SIZE:
777                 r_refdef.view.width = (int)(f[0]);
778                 r_refdef.view.height = (int)(f[1]);
779                 break;
780         case VF_SIZE_X:
781                 r_refdef.view.width = (int)(k);
782                 break;
783         case VF_SIZE_Y:
784                 r_refdef.view.height = (int)(k);
785                 break;
786         case VF_VIEWPORT:
787                 r_refdef.view.x = (int)(f[0]);
788                 r_refdef.view.y = (int)(f[1]);
789                 f = PRVM_G_VECTOR(OFS_PARM2);
790                 r_refdef.view.width = (int)(f[0]);
791                 r_refdef.view.height = (int)(f[1]);
792                 break;
793         case VF_FOV:
794                 r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
795                 r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
796                 break;
797         case VF_FOVX:
798                 r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
799                 break;
800         case VF_FOVY:
801                 r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
802                 break;
803         case VF_ORIGIN:
804                 VectorCopy(f, cl.csqc_origin);
805                 CSQC_R_RecalcView();
806                 break;
807         case VF_ORIGIN_X:
808                 cl.csqc_origin[0] = k;
809                 CSQC_R_RecalcView();
810                 break;
811         case VF_ORIGIN_Y:
812                 cl.csqc_origin[1] = k;
813                 CSQC_R_RecalcView();
814                 break;
815         case VF_ORIGIN_Z:
816                 cl.csqc_origin[2] = k;
817                 CSQC_R_RecalcView();
818                 break;
819         case VF_ANGLES:
820                 VectorCopy(f, cl.csqc_angles);
821                 CSQC_R_RecalcView();
822                 break;
823         case VF_ANGLES_X:
824                 cl.csqc_angles[0] = k;
825                 CSQC_R_RecalcView();
826                 break;
827         case VF_ANGLES_Y:
828                 cl.csqc_angles[1] = k;
829                 CSQC_R_RecalcView();
830                 break;
831         case VF_ANGLES_Z:
832                 cl.csqc_angles[2] = k;
833                 CSQC_R_RecalcView();
834                 break;
835         case VF_DRAWWORLD:
836                 cl.csqc_vidvars.drawworld = k;
837                 break;
838         case VF_DRAWENGINESBAR:
839                 cl.csqc_vidvars.drawenginesbar = k;
840                 break;
841         case VF_DRAWCROSSHAIR:
842                 cl.csqc_vidvars.drawcrosshair = k;
843                 break;
844         case VF_CL_VIEWANGLES:
845                 VectorCopy(f, cl.viewangles);
846                 break;
847         case VF_CL_VIEWANGLES_X:
848                 cl.viewangles[0] = k;
849                 break;
850         case VF_CL_VIEWANGLES_Y:
851                 cl.viewangles[1] = k;
852                 break;
853         case VF_CL_VIEWANGLES_Z:
854                 cl.viewangles[2] = k;
855                 break;
856         case VF_PERSPECTIVE:
857                 r_refdef.view.useperspective = k != 0;
858                 break;
859         case VF_CLEARSCREEN:
860                 r_refdef.view.isoverlay = !k;
861                 break;
862         default:
863                 PRVM_G_FLOAT(OFS_RETURN) = 0;
864                 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
865                 return;
866         }
867         PRVM_G_FLOAT(OFS_RETURN) = 1;
868 }
869
870 //#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC)
871 void VM_CL_R_AddDynamicLight (void)
872 {
873         vec_t *org;
874         float radius = 300;
875         vec_t *col;
876         int style = -1;
877         const char *cubemapname = NULL;
878         int pflags = PFLAGS_CORONA | PFLAGS_FULLDYNAMIC;
879         float coronaintensity = 1;
880         float coronasizescale = 0.25;
881         qboolean castshadow = true;
882         float ambientscale = 0;
883         float diffusescale = 1;
884         float specularscale = 1;
885         matrix4x4_t matrix;
886         vec3_t forward, left, up;
887         VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight);
888
889         // if we've run out of dlights, just return
890         if (r_refdef.scene.numlights >= MAX_DLIGHTS)
891                 return;
892
893         org = PRVM_G_VECTOR(OFS_PARM0);
894         radius = PRVM_G_FLOAT(OFS_PARM1);
895         col = PRVM_G_VECTOR(OFS_PARM2);
896         if (prog->argc >= 4)
897         {
898                 style = (int)PRVM_G_FLOAT(OFS_PARM3);
899                 if (style >= MAX_LIGHTSTYLES)
900                 {
901                         Con_DPrintf("VM_CL_R_AddDynamicLight: out of bounds lightstyle index %i\n", style);
902                         style = -1;
903                 }
904         }
905         if (prog->argc >= 5)
906                 cubemapname = PRVM_G_STRING(OFS_PARM4);
907         if (prog->argc >= 6)
908                 pflags = (int)PRVM_G_FLOAT(OFS_PARM5);
909         coronaintensity = (pflags & PFLAGS_CORONA) != 0;
910         castshadow = (pflags & PFLAGS_NOSHADOW) == 0;
911
912         VectorScale(prog->globals.client->v_forward, radius, forward);
913         VectorScale(prog->globals.client->v_right, -radius, left);
914         VectorScale(prog->globals.client->v_up, radius, up);
915         Matrix4x4_FromVectors(&matrix, forward, left, up, org);
916
917         R_RTLight_Update(&r_refdef.scene.lights[r_refdef.scene.numlights++], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
918 }
919
920 //============================================================================
921
922 //#310 vector (vector v) cs_unproject (EXT_CSQC)
923 static void VM_CL_unproject (void)
924 {
925         float   *f;
926         vec3_t  temp;
927
928         VM_SAFEPARMCOUNT(1, VM_CL_unproject);
929         f = PRVM_G_VECTOR(OFS_PARM0);
930         if(v_flipped.integer)
931                 f[0] = r_refdef.view.x + r_refdef.view.width - f[0];
932         VectorSet(temp, f[2], (-1.0 + 2.0 * (f[0] - r_refdef.view.x)) / r_refdef.view.width * f[2] * -r_refdef.view.frustum_x, (-1.0 + 2.0 * (f[1] - r_refdef.view.y))  / r_refdef.view.height * f[2] * -r_refdef.view.frustum_y);
933         Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
934 }
935
936 //#311 vector (vector v) cs_project (EXT_CSQC)
937 static void VM_CL_project (void)
938 {
939         float   *f;
940         vec3_t  v;
941         matrix4x4_t m;
942
943         VM_SAFEPARMCOUNT(1, VM_CL_project);
944         f = PRVM_G_VECTOR(OFS_PARM0);
945         Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
946         Matrix4x4_Transform(&m, f, v);
947         if(v_flipped.integer)
948                 v[1] = -v[1];
949         VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.x + r_refdef.view.width*0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x), r_refdef.view.y + r_refdef.view.height*0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y), v[0]);
950 }
951
952 //#330 float(float stnum) getstatf (EXT_CSQC)
953 static void VM_CL_getstatf (void)
954 {
955         int i;
956         union
957         {
958                 float f;
959                 int l;
960         }dat;
961         VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
962         i = (int)PRVM_G_FLOAT(OFS_PARM0);
963         if(i < 0 || i >= MAX_CL_STATS)
964         {
965                 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
966                 return;
967         }
968         dat.l = cl.stats[i];
969         PRVM_G_FLOAT(OFS_RETURN) =  dat.f;
970 }
971
972 //#331 float(float stnum) getstati (EXT_CSQC)
973 static void VM_CL_getstati (void)
974 {
975         int i, index;
976         int firstbit, bitcount;
977
978         VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
979
980         index = (int)PRVM_G_FLOAT(OFS_PARM0);
981         if (prog->argc > 1)
982         {
983                 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
984                 if (prog->argc > 2)
985                         bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
986                 else
987                         bitcount = 1;
988         }
989         else
990         {
991                 firstbit = 0;
992                 bitcount = 32;
993         }
994
995         if(index < 0 || index >= MAX_CL_STATS)
996         {
997                 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
998                 return;
999         }
1000         i = cl.stats[index];
1001         if (bitcount != 32)     //32 causes the mask to overflow, so there's nothing to subtract from.
1002                 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
1003         PRVM_G_FLOAT(OFS_RETURN) = i;
1004 }
1005
1006 //#332 string(float firststnum) getstats (EXT_CSQC)
1007 static void VM_CL_getstats (void)
1008 {
1009         int i;
1010         char t[17];
1011         VM_SAFEPARMCOUNT(1, VM_CL_getstats);
1012         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1013         if(i < 0 || i > MAX_CL_STATS-4)
1014         {
1015                 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1016                 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
1017                 return;
1018         }
1019         strlcpy(t, (char*)&cl.stats[i], sizeof(t));
1020         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1021 }
1022
1023 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
1024 static void VM_CL_setmodelindex (void)
1025 {
1026         int                             i;
1027         prvm_edict_t    *t;
1028         struct model_s  *model;
1029
1030         VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
1031
1032         t = PRVM_G_EDICT(OFS_PARM0);
1033
1034         i = (int)PRVM_G_FLOAT(OFS_PARM1);
1035
1036         t->fields.client->model = 0;
1037         t->fields.client->modelindex = 0;
1038
1039         if (!i)
1040                 return;
1041
1042         model = CL_GetModelByIndex(i);
1043         if (!model)
1044         {
1045                 VM_Warning("VM_CL_setmodelindex: null model\n");
1046                 return;
1047         }
1048         t->fields.client->model = PRVM_SetEngineString(model->name);
1049         t->fields.client->modelindex = i;
1050
1051         // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
1052         if (model)
1053         {
1054                 SetMinMaxSize (t, model->normalmins, model->normalmaxs);
1055         }
1056         else
1057                 SetMinMaxSize (t, vec3_origin, vec3_origin);
1058 }
1059
1060 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
1061 static void VM_CL_modelnameforindex (void)
1062 {
1063         dp_model_t *model;
1064
1065         VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
1066
1067         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1068         model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
1069         PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
1070 }
1071
1072 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
1073 static void VM_CL_particleeffectnum (void)
1074 {
1075         int                     i;
1076         VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
1077         i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
1078         if (i == 0)
1079                 i = -1;
1080         PRVM_G_FLOAT(OFS_RETURN) = i;
1081 }
1082
1083 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
1084 static void VM_CL_trailparticles (void)
1085 {
1086         int                             i;
1087         float                   *start, *end;
1088         prvm_edict_t    *t;
1089         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
1090
1091         t = PRVM_G_EDICT(OFS_PARM0);
1092         i               = (int)PRVM_G_FLOAT(OFS_PARM1);
1093         start   = PRVM_G_VECTOR(OFS_PARM2);
1094         end             = PRVM_G_VECTOR(OFS_PARM3);
1095
1096         if (i < 0)
1097                 return;
1098         CL_ParticleEffect(i, VectorDistance(start, end), start, end, t->fields.client->velocity, t->fields.client->velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1099 }
1100
1101 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
1102 static void VM_CL_pointparticles (void)
1103 {
1104         int                     i, n;
1105         float           *f, *v;
1106         VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
1107         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1108         f = PRVM_G_VECTOR(OFS_PARM1);
1109         v = PRVM_G_VECTOR(OFS_PARM2);
1110         n = (int)PRVM_G_FLOAT(OFS_PARM3);
1111         if (i < 0)
1112                 return;
1113         CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1114 }
1115
1116 //#342 string(float keynum) getkeybind (EXT_CSQC)
1117 static void VM_CL_getkeybind (void)
1118 {
1119         VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
1120         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
1121 }
1122
1123 //#343 void(float usecursor) setcursormode (EXT_CSQC)
1124 static void VM_CL_setcursormode (void)
1125 {
1126         VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
1127         cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
1128         cl_ignoremousemoves = 2;
1129 }
1130
1131 //#344 vector() getmousepos (EXT_CSQC)
1132 static void VM_CL_getmousepos(void)
1133 {
1134         VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
1135
1136         if (key_consoleactive || key_dest != key_game)
1137                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0);
1138         else if (cl.csqc_wantsmousemove)
1139                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
1140         else
1141                 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
1142 }
1143
1144 //#345 float(float framenum) getinputstate (EXT_CSQC)
1145 static void VM_CL_getinputstate (void)
1146 {
1147         int i, frame;
1148         VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1149         frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1150         for (i = 0;i < CL_MAX_USERCMDS;i++)
1151         {
1152                 if (cl.movecmd[i].sequence == frame)
1153                 {
1154                         VectorCopy(cl.movecmd[i].viewangles, prog->globals.client->input_angles);
1155                         prog->globals.client->input_buttons = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?)
1156                         prog->globals.client->input_movevalues[0] = cl.movecmd[i].forwardmove;
1157                         prog->globals.client->input_movevalues[1] = cl.movecmd[i].sidemove;
1158                         prog->globals.client->input_movevalues[2] = cl.movecmd[i].upmove;
1159                         prog->globals.client->input_timelength = cl.movecmd[i].frametime;
1160                         if(cl.movecmd[i].crouch)
1161                         {
1162                                 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1163                                 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1164                         }
1165                         else
1166                         {
1167                                 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1168                                 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1169                         }
1170                 }
1171         }
1172 }
1173
1174 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1175 static void VM_CL_setsensitivityscale (void)
1176 {
1177         VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1178         cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1179 }
1180
1181 //#347 void() runstandardplayerphysics (EXT_CSQC)
1182 static void VM_CL_runplayerphysics (void)
1183 {
1184 }
1185
1186 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1187 static void VM_CL_getplayerkey (void)
1188 {
1189         int                     i;
1190         char            t[128];
1191         const char      *c;
1192
1193         VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1194
1195         i = (int)PRVM_G_FLOAT(OFS_PARM0);
1196         c = PRVM_G_STRING(OFS_PARM1);
1197         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1198         Sbar_SortFrags();
1199
1200         if (i < 0)
1201                 i = Sbar_GetSortedPlayerIndex(-1-i);
1202         if(i < 0 || i >= cl.maxclients)
1203                 return;
1204
1205         t[0] = 0;
1206
1207         if(!strcasecmp(c, "name"))
1208                 strlcpy(t, cl.scores[i].name, sizeof(t));
1209         else
1210                 if(!strcasecmp(c, "frags"))
1211                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].frags);
1212         else
1213                 if(!strcasecmp(c, "ping"))
1214                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_ping);
1215         else
1216                 if(!strcasecmp(c, "pl"))
1217                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_packetloss);
1218         else
1219                 if(!strcasecmp(c, "entertime"))
1220                         dpsnprintf(t, sizeof(t), "%f", cl.scores[i].qw_entertime);
1221         else
1222                 if(!strcasecmp(c, "colors"))
1223                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors);
1224         else
1225                 if(!strcasecmp(c, "topcolor"))
1226                         dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors & 0xf0);
1227         else
1228                 if(!strcasecmp(c, "bottomcolor"))
1229                         dpsnprintf(t, sizeof(t), "%i", (cl.scores[i].colors &15)<<4);
1230         else
1231                 if(!strcasecmp(c, "viewentity"))
1232                         dpsnprintf(t, sizeof(t), "%i", i+1);
1233         if(!t[0])
1234                 return;
1235         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1236 }
1237
1238 //#349 float() isdemo (EXT_CSQC)
1239 static void VM_CL_isdemo (void)
1240 {
1241         VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1242         PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1243 }
1244
1245 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1246 static void VM_CL_setlistener (void)
1247 {
1248         VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1249         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));
1250         cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1251 }
1252
1253 //#352 void(string cmdname) registercommand (EXT_CSQC)
1254 static void VM_CL_registercmd (void)
1255 {
1256         char *t;
1257         VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1258         if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1259         {
1260                 size_t alloclen;
1261
1262                 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1263                 t = (char *)Z_Malloc(alloclen);
1264                 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1265                 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1266         }
1267         else
1268                 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1269
1270 }
1271
1272 //#360 float() readbyte (EXT_CSQC)
1273 static void VM_CL_ReadByte (void)
1274 {
1275         VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1276         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1277 }
1278
1279 //#361 float() readchar (EXT_CSQC)
1280 static void VM_CL_ReadChar (void)
1281 {
1282         VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1283         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1284 }
1285
1286 //#362 float() readshort (EXT_CSQC)
1287 static void VM_CL_ReadShort (void)
1288 {
1289         VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1290         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1291 }
1292
1293 //#363 float() readlong (EXT_CSQC)
1294 static void VM_CL_ReadLong (void)
1295 {
1296         VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1297         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1298 }
1299
1300 //#364 float() readcoord (EXT_CSQC)
1301 static void VM_CL_ReadCoord (void)
1302 {
1303         VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1304         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1305 }
1306
1307 //#365 float() readangle (EXT_CSQC)
1308 static void VM_CL_ReadAngle (void)
1309 {
1310         VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1311         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1312 }
1313
1314 //#366 string() readstring (EXT_CSQC)
1315 static void VM_CL_ReadString (void)
1316 {
1317         VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1318         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1319 }
1320
1321 //#367 float() readfloat (EXT_CSQC)
1322 static void VM_CL_ReadFloat (void)
1323 {
1324         VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1325         PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1326 }
1327
1328 //#501 string() readpicture (DP_CSQC_READWRITEPICTURE)
1329 extern cvar_t cl_readpicture_force;
1330 static void VM_CL_ReadPicture (void)
1331 {
1332         const char *name;
1333         unsigned char *data;
1334         unsigned char *buf;
1335         int size;
1336         int i;
1337         cachepic_t *pic;
1338
1339         VM_SAFEPARMCOUNT(0, VM_CL_ReadPicture);
1340
1341         name = MSG_ReadString();
1342         size = MSG_ReadShort();
1343
1344         // check if a texture of that name exists
1345         // if yes, it is used and the data is discarded
1346         // if not, the (low quality) data is used to build a new texture, whose name will get returned
1347
1348         pic = Draw_CachePic_Flags (name, CACHEPICFLAG_NOTPERSISTENT);
1349
1350         if(size)
1351         {
1352                 if(pic->tex == r_texture_notexture)
1353                         pic->tex = NULL; // don't overwrite the notexture by Draw_NewPic
1354                 if(pic->tex && !cl_readpicture_force.integer)
1355                 {
1356                         // texture found and loaded
1357                         // skip over the jpeg as we don't need it
1358                         for(i = 0; i < size; ++i)
1359                                 MSG_ReadByte();
1360                 }
1361                 else
1362                 {
1363                         // texture not found
1364                         // use the attached jpeg as texture
1365                         buf = Mem_Alloc(tempmempool, size);
1366                         MSG_ReadBytes(size, buf);
1367                         data = JPEG_LoadImage_BGRA(buf, size);
1368                         Mem_Free(buf);
1369                         Draw_NewPic(name, image_width, image_height, false, data);
1370                         Mem_Free(data);
1371                 }
1372         }
1373
1374         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(name);
1375 }
1376
1377 //////////////////////////////////////////////////////////
1378
1379 static void VM_CL_makestatic (void)
1380 {
1381         prvm_edict_t *ent;
1382
1383         VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1384
1385         ent = PRVM_G_EDICT(OFS_PARM0);
1386         if (ent == prog->edicts)
1387         {
1388                 VM_Warning("makestatic: can not modify world entity\n");
1389                 return;
1390         }
1391         if (ent->priv.server->free)
1392         {
1393                 VM_Warning("makestatic: can not modify free entity\n");
1394                 return;
1395         }
1396
1397         if (cl.num_static_entities < cl.max_static_entities)
1398         {
1399                 int renderflags;
1400                 prvm_eval_t *val;
1401                 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1402
1403                 // copy it to the current state
1404                 memset(staticent, 0, sizeof(*staticent));
1405                 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1406                 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1407                 staticent->render.framelerp = 0;
1408                 // make torchs play out of sync
1409                 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1410                 staticent->render.skinnum = (int)ent->fields.client->skin;
1411                 staticent->render.effects = (int)ent->fields.client->effects;
1412                 staticent->render.alpha = 1;
1413                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1414                 staticent->render.scale = 1;
1415                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1416                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1417
1418                 renderflags = 0;
1419                 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1420                 if (renderflags & RF_USEAXIS)
1421                 {
1422                         vec3_t left;
1423                         VectorNegate(prog->globals.client->v_right, left);
1424                         Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1425                         Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1426                 }
1427                 else
1428                         Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], staticent->render.scale);
1429
1430                 // either fullbright or lit
1431                 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1432                         staticent->render.flags |= RENDER_LIGHT;
1433                 // turn off shadows from transparent objects
1434                 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1435                         staticent->render.flags |= RENDER_SHADOW;
1436
1437                 CL_UpdateRenderEntity(&staticent->render);
1438         }
1439         else
1440                 Con_Printf("Too many static entities");
1441
1442 // throw the entity away now
1443         PRVM_ED_Free (ent);
1444 }
1445
1446 //=================================================================//
1447
1448 /*
1449 =================
1450 VM_CL_copyentity
1451
1452 copies data from one entity to another
1453
1454 copyentity(src, dst)
1455 =================
1456 */
1457 static void VM_CL_copyentity (void)
1458 {
1459         prvm_edict_t *in, *out;
1460         VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1461         in = PRVM_G_EDICT(OFS_PARM0);
1462         if (in == prog->edicts)
1463         {
1464                 VM_Warning("copyentity: can not read world entity\n");
1465                 return;
1466         }
1467         if (in->priv.server->free)
1468         {
1469                 VM_Warning("copyentity: can not read free entity\n");
1470                 return;
1471         }
1472         out = PRVM_G_EDICT(OFS_PARM1);
1473         if (out == prog->edicts)
1474         {
1475                 VM_Warning("copyentity: can not modify world entity\n");
1476                 return;
1477         }
1478         if (out->priv.server->free)
1479         {
1480                 VM_Warning("copyentity: can not modify free entity\n");
1481                 return;
1482         }
1483         memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1484         CL_LinkEdict(out);
1485 }
1486
1487 //=================================================================//
1488
1489 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1490 static void VM_CL_effect (void)
1491 {
1492         VM_SAFEPARMCOUNT(5, VM_CL_effect);
1493         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));
1494 }
1495
1496 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1497 static void VM_CL_te_blood (void)
1498 {
1499         float   *pos;
1500         vec3_t  pos2;
1501         VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1502         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1503                 return;
1504         pos = PRVM_G_VECTOR(OFS_PARM0);
1505         CL_FindNonSolidLocation(pos, pos2, 4);
1506         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1507 }
1508
1509 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1510 static void VM_CL_te_bloodshower (void)
1511 {
1512         vec_t speed;
1513         vec3_t vel1, vel2;
1514         VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1515         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1516                 return;
1517         speed = PRVM_G_FLOAT(OFS_PARM2);
1518         vel1[0] = -speed;
1519         vel1[1] = -speed;
1520         vel1[2] = -speed;
1521         vel2[0] = speed;
1522         vel2[1] = speed;
1523         vel2[2] = speed;
1524         CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1525 }
1526
1527 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1528 static void VM_CL_te_explosionrgb (void)
1529 {
1530         float           *pos;
1531         vec3_t          pos2;
1532         matrix4x4_t     tempmatrix;
1533         VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1534         pos = PRVM_G_VECTOR(OFS_PARM0);
1535         CL_FindNonSolidLocation(pos, pos2, 10);
1536         CL_ParticleExplosion(pos2);
1537         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1538         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);
1539 }
1540
1541 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1542 static void VM_CL_te_particlecube (void)
1543 {
1544         VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1545         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));
1546 }
1547
1548 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1549 static void VM_CL_te_particlerain (void)
1550 {
1551         VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1552         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);
1553 }
1554
1555 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1556 static void VM_CL_te_particlesnow (void)
1557 {
1558         VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1559         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);
1560 }
1561
1562 // #411 void(vector org, vector vel, float howmany) te_spark
1563 static void VM_CL_te_spark (void)
1564 {
1565         float           *pos;
1566         vec3_t          pos2;
1567         VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1568
1569         pos = PRVM_G_VECTOR(OFS_PARM0);
1570         CL_FindNonSolidLocation(pos, pos2, 4);
1571         CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1572 }
1573
1574 extern cvar_t cl_sound_ric_gunshot;
1575 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1576 static void VM_CL_te_gunshotquad (void)
1577 {
1578         float           *pos;
1579         vec3_t          pos2;
1580         int                     rnd;
1581         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1582
1583         pos = PRVM_G_VECTOR(OFS_PARM0);
1584         CL_FindNonSolidLocation(pos, pos2, 4);
1585         CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1586         if(cl_sound_ric_gunshot.integer >= 2)
1587         {
1588                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1589                 else
1590                 {
1591                         rnd = rand() & 3;
1592                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1593                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1594                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1595                 }
1596         }
1597 }
1598
1599 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1600 static void VM_CL_te_spikequad (void)
1601 {
1602         float           *pos;
1603         vec3_t          pos2;
1604         int                     rnd;
1605         VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1606
1607         pos = PRVM_G_VECTOR(OFS_PARM0);
1608         CL_FindNonSolidLocation(pos, pos2, 4);
1609         CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1610         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1611         else
1612         {
1613                 rnd = rand() & 3;
1614                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1615                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1616                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1617         }
1618 }
1619
1620 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1621 static void VM_CL_te_superspikequad (void)
1622 {
1623         float           *pos;
1624         vec3_t          pos2;
1625         int                     rnd;
1626         VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1627
1628         pos = PRVM_G_VECTOR(OFS_PARM0);
1629         CL_FindNonSolidLocation(pos, pos2, 4);
1630         CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1631         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1632         else
1633         {
1634                 rnd = rand() & 3;
1635                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1636                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1637                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1638         }
1639 }
1640
1641 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1642 static void VM_CL_te_explosionquad (void)
1643 {
1644         float           *pos;
1645         vec3_t          pos2;
1646         VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1647
1648         pos = PRVM_G_VECTOR(OFS_PARM0);
1649         CL_FindNonSolidLocation(pos, pos2, 10);
1650         CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1651         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1652 }
1653
1654 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1655 static void VM_CL_te_smallflash (void)
1656 {
1657         float           *pos;
1658         vec3_t          pos2;
1659         VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1660
1661         pos = PRVM_G_VECTOR(OFS_PARM0);
1662         CL_FindNonSolidLocation(pos, pos2, 10);
1663         CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1664 }
1665
1666 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1667 static void VM_CL_te_customflash (void)
1668 {
1669         float           *pos;
1670         vec3_t          pos2;
1671         matrix4x4_t     tempmatrix;
1672         VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1673
1674         pos = PRVM_G_VECTOR(OFS_PARM0);
1675         CL_FindNonSolidLocation(pos, pos2, 4);
1676         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1677         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);
1678 }
1679
1680 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1681 static void VM_CL_te_gunshot (void)
1682 {
1683         float           *pos;
1684         vec3_t          pos2;
1685         int                     rnd;
1686         VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1687
1688         pos = PRVM_G_VECTOR(OFS_PARM0);
1689         CL_FindNonSolidLocation(pos, pos2, 4);
1690         CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1691         if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1692         {
1693                 if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1694                 else
1695                 {
1696                         rnd = rand() & 3;
1697                         if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1698                         else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1699                         else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1700                 }
1701         }
1702 }
1703
1704 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1705 static void VM_CL_te_spike (void)
1706 {
1707         float           *pos;
1708         vec3_t          pos2;
1709         int                     rnd;
1710         VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1711
1712         pos = PRVM_G_VECTOR(OFS_PARM0);
1713         CL_FindNonSolidLocation(pos, pos2, 4);
1714         CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1715         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1716         else
1717         {
1718                 rnd = rand() & 3;
1719                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1720                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1721                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1722         }
1723 }
1724
1725 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1726 static void VM_CL_te_superspike (void)
1727 {
1728         float           *pos;
1729         vec3_t          pos2;
1730         int                     rnd;
1731         VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1732
1733         pos = PRVM_G_VECTOR(OFS_PARM0);
1734         CL_FindNonSolidLocation(pos, pos2, 4);
1735         CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1736         if (rand() % 5)                 S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1737         else
1738         {
1739                 rnd = rand() & 3;
1740                 if (rnd == 1)           S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1741                 else if (rnd == 2)      S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1742                 else                            S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1743         }
1744 }
1745
1746 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1747 static void VM_CL_te_explosion (void)
1748 {
1749         float           *pos;
1750         vec3_t          pos2;
1751         VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1752
1753         pos = PRVM_G_VECTOR(OFS_PARM0);
1754         CL_FindNonSolidLocation(pos, pos2, 10);
1755         CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1756         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1757 }
1758
1759 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1760 static void VM_CL_te_tarexplosion (void)
1761 {
1762         float           *pos;
1763         vec3_t          pos2;
1764         VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1765
1766         pos = PRVM_G_VECTOR(OFS_PARM0);
1767         CL_FindNonSolidLocation(pos, pos2, 10);
1768         CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1769         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1770 }
1771
1772 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1773 static void VM_CL_te_wizspike (void)
1774 {
1775         float           *pos;
1776         vec3_t          pos2;
1777         VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1778
1779         pos = PRVM_G_VECTOR(OFS_PARM0);
1780         CL_FindNonSolidLocation(pos, pos2, 4);
1781         CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1782         S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1783 }
1784
1785 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1786 static void VM_CL_te_knightspike (void)
1787 {
1788         float           *pos;
1789         vec3_t          pos2;
1790         VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1791
1792         pos = PRVM_G_VECTOR(OFS_PARM0);
1793         CL_FindNonSolidLocation(pos, pos2, 4);
1794         CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1795         S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1796 }
1797
1798 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1799 static void VM_CL_te_lavasplash (void)
1800 {
1801         VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1802         CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1803 }
1804
1805 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1806 static void VM_CL_te_teleport (void)
1807 {
1808         VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1809         CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1810 }
1811
1812 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1813 static void VM_CL_te_explosion2 (void)
1814 {
1815         float           *pos;
1816         vec3_t          pos2, color;
1817         matrix4x4_t     tempmatrix;
1818         int                     colorStart, colorLength;
1819         unsigned char           *tempcolor;
1820         VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1821
1822         pos = PRVM_G_VECTOR(OFS_PARM0);
1823         colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1824         colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1825         CL_FindNonSolidLocation(pos, pos2, 10);
1826         CL_ParticleExplosion2(pos2, colorStart, colorLength);
1827         tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
1828         color[0] = tempcolor[0] * (2.0f / 255.0f);
1829         color[1] = tempcolor[1] * (2.0f / 255.0f);
1830         color[2] = tempcolor[2] * (2.0f / 255.0f);
1831         Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1832         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);
1833         S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1834 }
1835
1836
1837 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1838 static void VM_CL_te_lightning1 (void)
1839 {
1840         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1841         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1842 }
1843
1844 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1845 static void VM_CL_te_lightning2 (void)
1846 {
1847         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1848         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1849 }
1850
1851 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1852 static void VM_CL_te_lightning3 (void)
1853 {
1854         VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1855         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1856 }
1857
1858 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1859 static void VM_CL_te_beam (void)
1860 {
1861         VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1862         CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1863 }
1864
1865 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1866 static void VM_CL_te_plasmaburn (void)
1867 {
1868         float           *pos;
1869         vec3_t          pos2;
1870         VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1871
1872         pos = PRVM_G_VECTOR(OFS_PARM0);
1873         CL_FindNonSolidLocation(pos, pos2, 4);
1874         CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1875 }
1876
1877 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1878 static void VM_CL_te_flamejet (void)
1879 {
1880         float *pos;
1881         vec3_t pos2;
1882         VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1883         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1884                 return;
1885         pos = PRVM_G_VECTOR(OFS_PARM0);
1886         CL_FindNonSolidLocation(pos, pos2, 4);
1887         CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1888 }
1889
1890
1891 //====================================================================
1892 //DP_QC_GETSURFACE
1893
1894 extern void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1895
1896 static msurface_t *cl_getsurface(dp_model_t *model, int surfacenum)
1897 {
1898         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1899                 return NULL;
1900         return model->data_surfaces + surfacenum + model->firstmodelsurface;
1901 }
1902
1903 // #434 float(entity e, float s) getsurfacenumpoints
1904 static void VM_CL_getsurfacenumpoints(void)
1905 {
1906         dp_model_t *model;
1907         msurface_t *surface;
1908         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1909         // return 0 if no such surface
1910         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1911         {
1912                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1913                 return;
1914         }
1915
1916         // note: this (incorrectly) assumes it is a simple polygon
1917         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1918 }
1919
1920 // #435 vector(entity e, float s, float n) getsurfacepoint
1921 static void VM_CL_getsurfacepoint(void)
1922 {
1923         prvm_edict_t *ed;
1924         dp_model_t *model;
1925         msurface_t *surface;
1926         int pointnum;
1927         VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1928         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1929         ed = PRVM_G_EDICT(OFS_PARM0);
1930         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1931                 return;
1932         // note: this (incorrectly) assumes it is a simple polygon
1933         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1934         if (pointnum < 0 || pointnum >= surface->num_vertices)
1935                 return;
1936         // FIXME: implement rotation/scaling
1937         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1938 }
1939 //PF_getsurfacepointattribute,     // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
1940 // float SPA_POSITION = 0;
1941 // float SPA_S_AXIS = 1;
1942 // float SPA_T_AXIS = 2;
1943 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1944 // float SPA_TEXCOORDS0 = 4;
1945 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1946 // float SPA_LIGHTMAP0_COLOR = 6;
1947 // TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black]
1948 static void VM_CL_getsurfacepointattribute(void)
1949 {
1950         prvm_edict_t *ed;
1951         dp_model_t *model;
1952         msurface_t *surface;
1953         int pointnum;
1954         int attributetype;
1955
1956         VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints);
1957         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1958         ed = PRVM_G_EDICT(OFS_PARM0);
1959         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1960                 return;
1961         // note: this (incorrectly) assumes it is a simple polygon
1962         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1963         if (pointnum < 0 || pointnum >= surface->num_vertices)
1964                 return;
1965
1966         // FIXME: implement rotation/scaling
1967         attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
1968
1969         switch( attributetype ) {
1970                 // float SPA_POSITION = 0;
1971                 case 0:
1972                         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1973                         break;
1974                 // float SPA_S_AXIS = 1;
1975                 case 1:
1976                         VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1977                         break;
1978                 // float SPA_T_AXIS = 2;
1979                 case 2:
1980                         VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1981                         break;
1982                 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1983                 case 3:
1984                         VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1985                         break;
1986                 // float SPA_TEXCOORDS0 = 4;
1987                 case 4: {
1988                         float *ret = PRVM_G_VECTOR(OFS_RETURN);
1989                         float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
1990                         ret[0] = texcoord[0];
1991                         ret[1] = texcoord[1];
1992                         ret[2] = 0.0f;
1993                         break;
1994                 }
1995                 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1996                 case 5: {
1997                         float *ret = PRVM_G_VECTOR(OFS_RETURN);
1998                         float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
1999                         ret[0] = texcoord[0];
2000                         ret[1] = texcoord[1];
2001                         ret[2] = 0.0f;
2002                         break;
2003                 }
2004                 // float SPA_LIGHTMAP0_COLOR = 6;
2005                 case 6:
2006                         // ignore alpha for now..
2007                         VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2008                         break;
2009                 default:
2010                         VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2011                         break;
2012         }
2013 }
2014 // #436 vector(entity e, float s) getsurfacenormal
2015 static void VM_CL_getsurfacenormal(void)
2016 {
2017         dp_model_t *model;
2018         msurface_t *surface;
2019         vec3_t normal;
2020         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
2021         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2022         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2023                 return;
2024         // FIXME: implement rotation/scaling
2025         // note: this (incorrectly) assumes it is a simple polygon
2026         // note: this only returns the first triangle, so it doesn't work very
2027         // well for curved surfaces or arbitrary meshes
2028         TriangleNormal((model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 3, (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
2029         VectorNormalize(normal);
2030         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2031 }
2032
2033 // #437 string(entity e, float s) getsurfacetexture
2034 static void VM_CL_getsurfacetexture(void)
2035 {
2036         dp_model_t *model;
2037         msurface_t *surface;
2038         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
2039         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2040         if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2041                 return;
2042         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2043 }
2044
2045 // #438 float(entity e, vector p) getsurfacenearpoint
2046 static void VM_CL_getsurfacenearpoint(void)
2047 {
2048         int surfacenum, best;
2049         vec3_t clipped, p;
2050         vec_t dist, bestdist;
2051         prvm_edict_t *ed;
2052         dp_model_t *model = NULL;
2053         msurface_t *surface;
2054         vec_t *point;
2055         VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
2056         PRVM_G_FLOAT(OFS_RETURN) = -1;
2057         ed = PRVM_G_EDICT(OFS_PARM0);
2058         if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
2059                 return;
2060
2061         // FIXME: implement rotation/scaling
2062         point = PRVM_G_VECTOR(OFS_PARM1);
2063         VectorSubtract(point, ed->fields.client->origin, p);
2064         best = -1;
2065         bestdist = 1000000000;
2066         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2067         {
2068                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2069                 // first see if the nearest point on the surface's box is closer than the previous match
2070                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2071                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2072                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2073                 dist = VectorLength2(clipped);
2074                 if (dist < bestdist)
2075                 {
2076                         // it is, check the nearest point on the actual geometry
2077                         clippointtosurface(model, surface, p, clipped);
2078                         VectorSubtract(clipped, p, clipped);
2079                         dist += VectorLength2(clipped);
2080                         if (dist < bestdist)
2081                         {
2082                                 // that's closer too, store it as the best match
2083                                 best = surfacenum;
2084                                 bestdist = dist;
2085                         }
2086                 }
2087         }
2088         PRVM_G_FLOAT(OFS_RETURN) = best;
2089 }
2090
2091 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
2092 static void VM_CL_getsurfaceclippedpoint(void)
2093 {
2094         prvm_edict_t *ed;
2095         dp_model_t *model;
2096         msurface_t *surface;
2097         vec3_t p, out;
2098         VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
2099         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2100         ed = PRVM_G_EDICT(OFS_PARM0);
2101         if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2102                 return;
2103         // FIXME: implement rotation/scaling
2104         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
2105         clippointtosurface(model, surface, p, out);
2106         // FIXME: implement rotation/scaling
2107         VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
2108 }
2109
2110 // #443 void(entity e, entity tagentity, string tagname) setattachment
2111 void VM_CL_setattachment (void)
2112 {
2113         prvm_edict_t *e;
2114         prvm_edict_t *tagentity;
2115         const char *tagname;
2116         prvm_eval_t *v;
2117         int modelindex;
2118         dp_model_t *model;
2119         VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
2120
2121         e = PRVM_G_EDICT(OFS_PARM0);
2122         tagentity = PRVM_G_EDICT(OFS_PARM1);
2123         tagname = PRVM_G_STRING(OFS_PARM2);
2124
2125         if (e == prog->edicts)
2126         {
2127                 VM_Warning("setattachment: can not modify world entity\n");
2128                 return;
2129         }
2130         if (e->priv.server->free)
2131         {
2132                 VM_Warning("setattachment: can not modify free entity\n");
2133                 return;
2134         }
2135
2136         if (tagentity == NULL)
2137                 tagentity = prog->edicts;
2138
2139         v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2140         if (v)
2141                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2142
2143         v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2144         if (v)
2145                 v->_float = 0;
2146         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2147         {
2148                 modelindex = (int)tagentity->fields.client->modelindex;
2149                 model = CL_GetModelByIndex(modelindex);
2150                 if (model)
2151                 {
2152                         v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
2153                         if (v->_float == 0)
2154                                 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);
2155                 }
2156                 else
2157                         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));
2158         }
2159 }
2160
2161 /////////////////////////////////////////
2162 // DP_MD3_TAGINFO extension coded by VorteX
2163
2164 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
2165 {
2166         dp_model_t *model = CL_GetModelFromEdict(e);
2167         if (model)
2168                 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
2169         else
2170                 return -1;
2171 };
2172
2173 // Warnings/errors code:
2174 // 0 - normal (everything all-right)
2175 // 1 - world entity
2176 // 2 - free entity
2177 // 3 - null or non-precached model
2178 // 4 - no tags with requested index
2179 // 5 - runaway loop at attachment chain
2180 extern cvar_t cl_bob;
2181 extern cvar_t cl_bobcycle;
2182 extern cvar_t cl_bobup;
2183 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2184 {
2185         prvm_eval_t *val;
2186         int reqframe, attachloop;
2187         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2188         prvm_edict_t *attachent;
2189         dp_model_t *model;
2190         float scale;
2191
2192         *out = identitymatrix; // warnings and errors return identical matrix
2193
2194         if (ent == prog->edicts)
2195                 return 1;
2196         if (ent->priv.server->free)
2197                 return 2;
2198
2199         model = CL_GetModelFromEdict(ent);
2200
2201         if(!model)
2202                 return 3;
2203
2204         if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
2205                 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
2206         else
2207                 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2208
2209         // get initial tag matrix
2210         if (tagindex)
2211         {
2212                 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2213                 if (ret)
2214                         return ret;
2215         }
2216         else
2217                 tagmatrix = identitymatrix;
2218
2219         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2220         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2221                 attachloop = 0;
2222                 do
2223                 {
2224                         attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2225                         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
2226
2227                         model = CL_GetModelFromEdict(attachent);
2228
2229                         if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
2230                                 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
2231                         else
2232                                 attachmatrix = identitymatrix;
2233
2234                         // apply transformation by child entity matrix
2235                         scale = 1;
2236                         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2237                         if (val && val->_float != 0)
2238                                 scale = val->_float;
2239                         Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], -ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
2240                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2241                         Matrix4x4_Copy(&tagmatrix, out);
2242
2243                         // finally transformate by matrix of tag on parent entity
2244                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2245                         Matrix4x4_Copy(&tagmatrix, out);
2246
2247                         ent = attachent;
2248                         attachloop += 1;
2249                         if (attachloop > 255) // prevent runaway looping
2250                                 return 5;
2251                 }
2252                 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
2253         }
2254
2255         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2256         scale = 1;
2257         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2258         if (val && val->_float != 0)
2259                 scale = val->_float;
2260         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2261         Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], -ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
2262         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2263
2264         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
2265         {// RENDER_VIEWMODEL magic
2266                 Matrix4x4_Copy(&tagmatrix, out);
2267
2268                 scale = 1;
2269                 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2270                 if (val && val->_float != 0)
2271                         scale = val->_float;
2272
2273                 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], scale);
2274                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2275
2276                 /*
2277                 // Cl_bob, ported from rendering code
2278                 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2279                 {
2280                         double bob, cycle;
2281                         // LordHavoc: this code is *weird*, but not replacable (I think it
2282                         // should be done in QC on the server, but oh well, quake is quake)
2283                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2284                         // degrees (which allows lengthening or squishing the peak or valley)
2285                         cycle = cl.time/cl_bobcycle.value;
2286                         cycle -= (int)cycle;
2287                         if (cycle < cl_bobup.value)
2288                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2289                         else
2290                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2291                         // bob is proportional to velocity in the xy plane
2292                         // (don't count Z, or jumping messes it up)
2293                         bob = sqrt(ent->fields.client->velocity[0]*ent->fields.client->velocity[0] + ent->fields.client->velocity[1]*ent->fields.client->velocity[1])*cl_bob.value;
2294                         bob = bob*0.3 + bob*0.7*cycle;
2295                         Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2296                 }
2297                 */
2298         }
2299         return 0;
2300 }
2301
2302 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2303 void VM_CL_gettagindex (void)
2304 {
2305         prvm_edict_t *ent;
2306         const char *tag_name;
2307         int modelindex, tag_index;
2308
2309         VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2310
2311         ent = PRVM_G_EDICT(OFS_PARM0);
2312         tag_name = PRVM_G_STRING(OFS_PARM1);
2313         if (ent == prog->edicts)
2314         {
2315                 VM_Warning("gettagindex: can't affect world entity\n");
2316                 return;
2317         }
2318         if (ent->priv.server->free)
2319         {
2320                 VM_Warning("gettagindex: can't affect free entity\n");
2321                 return;
2322         }
2323
2324         modelindex = (int)ent->fields.client->modelindex;
2325         tag_index = 0;
2326         if (modelindex >= MAX_MODELS || (modelindex <= -MAX_MODELS /* client models */))
2327                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2328         else
2329         {
2330                 tag_index = CL_GetTagIndex(ent, tag_name);
2331                 if (tag_index == 0)
2332                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2333         }
2334         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2335 }
2336
2337 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2338 void VM_CL_gettaginfo (void)
2339 {
2340         prvm_edict_t *e;
2341         int tagindex;
2342         matrix4x4_t tag_matrix;
2343         int returncode;
2344
2345         VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2346
2347         e = PRVM_G_EDICT(OFS_PARM0);
2348         tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2349         returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2350         Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2351
2352         switch(returncode)
2353         {
2354                 case 1:
2355                         VM_Warning("gettagindex: can't affect world entity\n");
2356                         break;
2357                 case 2:
2358                         VM_Warning("gettagindex: can't affect free entity\n");
2359                         break;
2360                 case 3:
2361                         Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2362                         break;
2363                 case 4:
2364                         Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2365                         break;
2366                 case 5:
2367                         Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2368                         break;
2369         }
2370 }
2371
2372 //============================================================================
2373
2374 //====================
2375 //QC POLYGON functions
2376 //====================
2377
2378 #define VMPOLYGONS_MAXPOINTS 64
2379
2380 typedef struct vmpolygons_triangle_s
2381 {
2382         rtexture_t              *texture;
2383         int                             drawflag;
2384         unsigned short  elements[3];
2385 }vmpolygons_triangle_t;
2386
2387 typedef struct vmpolygons_s
2388 {
2389         mempool_t               *pool;
2390         qboolean                initialized;
2391         double          progstarttime;
2392
2393         int                             max_vertices;
2394         int                             num_vertices;
2395         float                   *data_vertex3f;
2396         float                   *data_color4f;
2397         float                   *data_texcoord2f;
2398
2399         int                             max_triangles;
2400         int                             num_triangles;
2401         vmpolygons_triangle_t *data_triangles;
2402         unsigned short  *data_sortedelement3s;
2403
2404         qboolean                begin_active;
2405         rtexture_t              *begin_texture;
2406         int                             begin_drawflag;
2407         int                             begin_vertices;
2408         float                   begin_vertex[VMPOLYGONS_MAXPOINTS][3];
2409         float                   begin_color[VMPOLYGONS_MAXPOINTS][4];
2410         float                   begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
2411 } vmpolygons_t;
2412
2413 // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
2414 vmpolygons_t vmpolygons[PRVM_MAXPROGS];
2415
2416 //#304 void() renderscene (EXT_CSQC)
2417 // moved that here to reset the polygons,
2418 // resetting them earlier causes R_Mesh_Draw to be called with numvertices = 0
2419 // --blub
2420 void VM_CL_R_RenderScene (void)
2421 {
2422         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2423         VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
2424         // we need to update any RENDER_VIEWMODEL entities at this point because
2425         // csqc supplies its own view matrix
2426         CL_UpdateViewEntities();
2427         // now draw stuff!
2428         R_RenderView();
2429
2430         polys->num_vertices = polys->num_triangles = 0;
2431         polys->progstarttime = prog->starttime;
2432 }
2433
2434 static void VM_ResizePolygons(vmpolygons_t *polys)
2435 {
2436         float *oldvertex3f = polys->data_vertex3f;
2437         float *oldcolor4f = polys->data_color4f;
2438         float *oldtexcoord2f = polys->data_texcoord2f;
2439         vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
2440         unsigned short *oldsortedelement3s = polys->data_sortedelement3s;
2441         polys->max_vertices = min(polys->max_triangles*3, 65536);
2442         polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
2443         polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
2444         polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
2445         polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
2446         polys->data_sortedelement3s = (unsigned short *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(unsigned short[3]));
2447         if (polys->num_vertices)
2448         {
2449                 memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
2450                 memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
2451                 memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
2452         }
2453         if (polys->num_triangles)
2454         {
2455                 memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
2456                 memcpy(polys->data_sortedelement3s, oldsortedelement3s, polys->num_triangles*sizeof(unsigned short[3]));
2457         }
2458         if (oldvertex3f)
2459                 Mem_Free(oldvertex3f);
2460         if (oldcolor4f)
2461                 Mem_Free(oldcolor4f);
2462         if (oldtexcoord2f)
2463                 Mem_Free(oldtexcoord2f);
2464         if (oldtriangles)
2465                 Mem_Free(oldtriangles);
2466         if (oldsortedelement3s)
2467                 Mem_Free(oldsortedelement3s);
2468 }
2469
2470 static void VM_InitPolygons (vmpolygons_t* polys)
2471 {
2472         memset(polys, 0, sizeof(*polys));
2473         polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
2474         polys->max_triangles = 1024;
2475         VM_ResizePolygons(polys);
2476         polys->initialized = true;
2477 }
2478
2479 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2480 {
2481         int surfacelistindex;
2482         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2483         if(polys->progstarttime != prog->starttime) // from other progs? won't draw these (this can cause crashes!)
2484                 return;
2485         R_Mesh_ResetTextureState();
2486         R_Mesh_Matrix(&identitymatrix);
2487         GL_CullFace(GL_NONE);
2488         R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
2489         R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
2490         R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
2491         R_SetupGenericShader(true);
2492
2493         for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
2494         {
2495                 int numtriangles = 0;
2496                 rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
2497                 int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
2498                 // this can't call _DrawQ_ProcessDrawFlag, but should be in sync with it
2499                 // FIXME factor this out
2500                 if(drawflag == DRAWFLAG_ADDITIVE)
2501                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2502                 else if(drawflag == DRAWFLAG_MODULATE)
2503                         GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2504                 else if(drawflag == DRAWFLAG_2XMODULATE)
2505                         GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2506                 else if(drawflag == DRAWFLAG_SCREEN)
2507                         GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
2508                 else
2509                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2510                 R_Mesh_TexBind(0, R_GetTexture(tex));
2511                 numtriangles = 0;
2512                 for (;surfacelistindex < numsurfaces;surfacelistindex++)
2513                 {
2514                         if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag)
2515                                 break;
2516                         VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles);
2517                         numtriangles++;
2518                 }
2519                 R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, polys->data_sortedelement3s, 0, 0);
2520         }
2521 }
2522
2523 void VMPolygons_Store(vmpolygons_t *polys)
2524 {
2525         if (r_refdef.draw2dstage)
2526         {
2527                 // draw the polygon as 2D immediately
2528                 drawqueuemesh_t mesh;
2529                 mesh.texture = polys->begin_texture;
2530                 mesh.num_vertices = polys->begin_vertices;
2531                 mesh.num_triangles = polys->begin_vertices-2;
2532                 mesh.data_element3s = polygonelements;
2533                 mesh.data_vertex3f = polys->begin_vertex[0];
2534                 mesh.data_color4f = polys->begin_color[0];
2535                 mesh.data_texcoord2f = polys->begin_texcoord[0];
2536                 DrawQ_Mesh(&mesh, polys->begin_drawflag);
2537         }
2538         else
2539         {
2540                 // queue the polygon as 3D for sorted transparent rendering later
2541                 int i;
2542                 if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2)
2543                 {
2544                         polys->max_triangles *= 2;
2545                         VM_ResizePolygons(polys);
2546                 }
2547                 if (polys->num_vertices + polys->begin_vertices <= polys->max_vertices)
2548                 {
2549                         // needle in a haystack!
2550                         // polys->num_vertices was used for copying where we actually want to copy begin_vertices
2551                         // that also caused it to not render the first polygon that is added
2552                         // --blub
2553                         memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->begin_vertices * sizeof(float[3]));
2554                         memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->begin_vertices * sizeof(float[4]));
2555                         memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->begin_vertices * sizeof(float[2]));
2556                         for (i = 0;i < polys->begin_vertices-2;i++)
2557                         {
2558                                 polys->data_triangles[polys->num_triangles].texture = polys->begin_texture;
2559                                 polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag;
2560                                 polys->data_triangles[polys->num_triangles].elements[0] = polys->num_vertices;
2561                                 polys->data_triangles[polys->num_triangles].elements[1] = polys->num_vertices + i+1;
2562                                 polys->data_triangles[polys->num_triangles].elements[2] = polys->num_vertices + i+2;
2563                                 polys->num_triangles++;
2564                         }
2565                         polys->num_vertices += polys->begin_vertices;
2566                 }
2567         }
2568         polys->begin_active = false;
2569 }
2570
2571 // TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
2572 // LordHavoc: agreed, this is a mess
2573 void VM_CL_AddPolygonsToMeshQueue (void)
2574 {
2575         int i;
2576         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2577         vec3_t center;
2578
2579         // only add polygons of the currently active prog to the queue - if there is none, we're done
2580         if( !prog )
2581                 return;
2582
2583         if (!polys->num_triangles)
2584                 return;
2585
2586         for (i = 0;i < polys->num_triangles;i++)
2587         {
2588                 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);
2589                 R_MeshQueue_AddTransparent(center, VM_DrawPolygonCallback, NULL, i, NULL);
2590         }
2591
2592         /*polys->num_triangles = 0; // now done after rendering the scene,
2593           polys->num_vertices = 0;  // otherwise it's not rendered at all and prints an error message --blub */
2594 }
2595
2596 //void(string texturename, float flag) R_BeginPolygon
2597 void VM_CL_R_PolygonBegin (void)
2598 {
2599         const char              *picname;
2600         skinframe_t     *sf;
2601         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2602         int tf;
2603
2604         // TODO instead of using skinframes here (which provides the benefit of
2605         // better management of flags, and is more suited for 3D rendering), what
2606         // about supporting Q3 shaders?
2607
2608         VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
2609
2610         if (!polys->initialized)
2611                 VM_InitPolygons(polys);
2612         if(polys->progstarttime != prog->starttime)
2613         {
2614                 // from another progs? then reset the polys first (fixes crashes on map change, because that can make skinframe textures invalid)
2615                 polys->num_vertices = polys->num_triangles = 0;
2616                 polys->progstarttime = prog->starttime;
2617         }
2618         if (polys->begin_active)
2619         {
2620                 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
2621                 return;
2622         }
2623         picname = PRVM_G_STRING(OFS_PARM0);
2624
2625         sf = NULL;
2626         if(*picname)
2627         {
2628                 tf = TEXF_ALPHA;
2629                 if((int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MIPMAP)
2630                         tf |= TEXF_MIPMAP;
2631
2632                 do
2633                 {
2634                         sf = R_SkinFrame_FindNextByName(sf, picname);
2635                 }
2636                 while(sf && sf->textureflags != tf);
2637
2638                 if(!sf || !sf->base)
2639                         sf = R_SkinFrame_LoadExternal(picname, tf, true);
2640
2641                 if(sf)
2642                         R_SkinFrame_MarkUsed(sf);
2643         }
2644
2645         polys->begin_texture = (sf && sf->base) ? sf->base : r_texture_white;
2646         polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MASK;
2647         polys->begin_vertices = 0;
2648         polys->begin_active = true;
2649 }
2650
2651 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2652 void VM_CL_R_PolygonVertex (void)
2653 {
2654         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2655
2656         VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2657
2658         if (!polys->begin_active)
2659         {
2660                 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2661                 return;
2662         }
2663
2664         if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
2665         {
2666                 VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2667                 return;
2668         }
2669
2670         polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0];
2671         polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1];
2672         polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2];
2673         polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0];
2674         polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1];
2675         polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0];
2676         polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1];
2677         polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2];
2678         polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3);
2679         polys->begin_vertices++;
2680 }
2681
2682 //void() R_EndPolygon
2683 void VM_CL_R_PolygonEnd (void)
2684 {
2685         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2686
2687         VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2688         if (!polys->begin_active)
2689         {
2690                 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2691                 return;
2692         }
2693         polys->begin_active = false;
2694         if (polys->begin_vertices >= 3)
2695                 VMPolygons_Store(polys);
2696         else
2697                 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
2698 }
2699
2700 static vmpolygons_t debugPolys;
2701
2702 void Debug_PolygonBegin(const char *picname, int drawflag)
2703 {
2704         if(!debugPolys.initialized)
2705                 VM_InitPolygons(&debugPolys);
2706         if(debugPolys.begin_active)
2707         {
2708                 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2709                 return;
2710         }
2711         debugPolys.begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white;
2712         debugPolys.begin_drawflag = drawflag;
2713         debugPolys.begin_vertices = 0;
2714         debugPolys.begin_active = true;
2715 }
2716
2717 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2718 {
2719         if(!debugPolys.begin_active)
2720         {
2721                 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2722                 return;
2723         }
2724
2725         if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS)
2726         {
2727                 Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2728                 return;
2729         }
2730
2731         debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x;
2732         debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y;
2733         debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z;
2734         debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s;
2735         debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t;
2736         debugPolys.begin_color[debugPolys.begin_vertices][0] = r;
2737         debugPolys.begin_color[debugPolys.begin_vertices][1] = g;
2738         debugPolys.begin_color[debugPolys.begin_vertices][2] = b;
2739         debugPolys.begin_color[debugPolys.begin_vertices][3] = a;
2740         debugPolys.begin_vertices++;
2741 }
2742
2743 void Debug_PolygonEnd(void)
2744 {
2745         if (!debugPolys.begin_active)
2746         {
2747                 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2748                 return;
2749         }
2750         debugPolys.begin_active = false;
2751         if (debugPolys.begin_vertices >= 3)
2752                 VMPolygons_Store(&debugPolys);
2753         else
2754                 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
2755 }
2756
2757 /*
2758 =============
2759 CL_CheckBottom
2760
2761 Returns false if any part of the bottom of the entity is off an edge that
2762 is not a staircase.
2763
2764 =============
2765 */
2766 qboolean CL_CheckBottom (prvm_edict_t *ent)
2767 {
2768         vec3_t  mins, maxs, start, stop;
2769         trace_t trace;
2770         int             x, y;
2771         float   mid, bottom;
2772
2773         VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2774         VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2775
2776 // if all of the points under the corners are solid world, don't bother
2777 // with the tougher checks
2778 // the corners must be within 16 of the midpoint
2779         start[2] = mins[2] - 1;
2780         for     (x=0 ; x<=1 ; x++)
2781                 for     (y=0 ; y<=1 ; y++)
2782                 {
2783                         start[0] = x ? maxs[0] : mins[0];
2784                         start[1] = y ? maxs[1] : mins[1];
2785                         if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2786                                 goto realcheck;
2787                 }
2788
2789         return true;            // we got out easy
2790
2791 realcheck:
2792 //
2793 // check it for real...
2794 //
2795         start[2] = mins[2];
2796
2797 // the midpoint must be within 16 of the bottom
2798         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2799         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2800         stop[2] = start[2] - 2*sv_stepheight.value;
2801         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2802
2803         if (trace.fraction == 1.0)
2804                 return false;
2805         mid = bottom = trace.endpos[2];
2806
2807 // the corners must be within 16 of the midpoint
2808         for     (x=0 ; x<=1 ; x++)
2809                 for     (y=0 ; y<=1 ; y++)
2810                 {
2811                         start[0] = stop[0] = x ? maxs[0] : mins[0];
2812                         start[1] = stop[1] = y ? maxs[1] : mins[1];
2813
2814                         trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2815
2816                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2817                                 bottom = trace.endpos[2];
2818                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2819                                 return false;
2820                 }
2821
2822         return true;
2823 }
2824
2825 /*
2826 =============
2827 CL_movestep
2828
2829 Called by monster program code.
2830 The move will be adjusted for slopes and stairs, but if the move isn't
2831 possible, no move is done and false is returned
2832 =============
2833 */
2834 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2835 {
2836         float           dz;
2837         vec3_t          oldorg, neworg, end, traceendpos;
2838         trace_t         trace;
2839         int                     i, svent;
2840         prvm_edict_t            *enemy;
2841         prvm_eval_t     *val;
2842
2843 // try the move
2844         VectorCopy (ent->fields.client->origin, oldorg);
2845         VectorAdd (ent->fields.client->origin, move, neworg);
2846
2847 // flying monsters don't step up
2848         if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2849         {
2850         // try one move with vertical motion, then one without
2851                 for (i=0 ; i<2 ; i++)
2852                 {
2853                         VectorAdd (ent->fields.client->origin, move, neworg);
2854                         enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2855                         if (i == 0 && enemy != prog->edicts)
2856                         {
2857                                 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2858                                 if (dz > 40)
2859                                         neworg[2] -= 8;
2860                                 if (dz < 30)
2861                                         neworg[2] += 8;
2862                         }
2863                         trace = CL_Move (ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
2864                         if (settrace)
2865                                 CL_VM_SetTraceGlobals(&trace, svent);
2866
2867                         if (trace.fraction == 1)
2868                         {
2869                                 VectorCopy(trace.endpos, traceendpos);
2870                                 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2871                                         return false;   // swim monster left water
2872
2873                                 VectorCopy (traceendpos, ent->fields.client->origin);
2874                                 if (relink)
2875                                         CL_LinkEdict(ent);
2876                                 return true;
2877                         }
2878
2879                         if (enemy == prog->edicts)
2880                                 break;
2881                 }
2882
2883                 return false;
2884         }
2885
2886 // push down from a step height above the wished position
2887         neworg[2] += sv_stepheight.value;
2888         VectorCopy (neworg, end);
2889         end[2] -= sv_stepheight.value*2;
2890
2891         trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
2892         if (settrace)
2893                 CL_VM_SetTraceGlobals(&trace, svent);
2894
2895         if (trace.startsolid)
2896         {
2897                 neworg[2] -= sv_stepheight.value;
2898                 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
2899                 if (settrace)
2900                         CL_VM_SetTraceGlobals(&trace, svent);
2901                 if (trace.startsolid)
2902                         return false;
2903         }
2904         if (trace.fraction == 1)
2905         {
2906         // if monster had the ground pulled out, go ahead and fall
2907                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2908                 {
2909                         VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2910                         if (relink)
2911                                 CL_LinkEdict(ent);
2912                         ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2913                         return true;
2914                 }
2915
2916                 return false;           // walked off an edge
2917         }
2918
2919 // check point traces down for dangling corners
2920         VectorCopy (trace.endpos, ent->fields.client->origin);
2921
2922         if (!CL_CheckBottom (ent))
2923         {
2924                 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2925                 {       // entity had floor mostly pulled out from underneath it
2926                         // and is trying to correct
2927                         if (relink)
2928                                 CL_LinkEdict(ent);
2929                         return true;
2930                 }
2931                 VectorCopy (oldorg, ent->fields.client->origin);
2932                 return false;
2933         }
2934
2935         if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2936                 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2937
2938         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2939                 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2940
2941 // the move is ok
2942         if (relink)
2943                 CL_LinkEdict(ent);
2944         return true;
2945 }
2946
2947 /*
2948 ===============
2949 VM_CL_walkmove
2950
2951 float(float yaw, float dist[, settrace]) walkmove
2952 ===============
2953 */
2954 static void VM_CL_walkmove (void)
2955 {
2956         prvm_edict_t    *ent;
2957         float   yaw, dist;
2958         vec3_t  move;
2959         mfunction_t     *oldf;
2960         int     oldself;
2961         qboolean        settrace;
2962
2963         VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2964
2965         // assume failure if it returns early
2966         PRVM_G_FLOAT(OFS_RETURN) = 0;
2967
2968         ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2969         if (ent == prog->edicts)
2970         {
2971                 VM_Warning("walkmove: can not modify world entity\n");
2972                 return;
2973         }
2974         if (ent->priv.server->free)
2975         {
2976                 VM_Warning("walkmove: can not modify free entity\n");
2977                 return;
2978         }
2979         yaw = PRVM_G_FLOAT(OFS_PARM0);
2980         dist = PRVM_G_FLOAT(OFS_PARM1);
2981         settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2982
2983         if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2984                 return;
2985
2986         yaw = yaw*M_PI*2 / 360;
2987
2988         move[0] = cos(yaw)*dist;
2989         move[1] = sin(yaw)*dist;
2990         move[2] = 0;
2991
2992 // save program state, because CL_movestep may call other progs
2993         oldf = prog->xfunction;
2994         oldself = prog->globals.client->self;
2995
2996         PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2997
2998
2999 // restore program state
3000         prog->xfunction = oldf;
3001         prog->globals.client->self = oldself;
3002 }
3003
3004 /*
3005 ===============
3006 VM_CL_serverkey
3007
3008 string(string key) serverkey
3009 ===============
3010 */
3011 void VM_CL_serverkey(void)
3012 {
3013         char string[VM_STRINGTEMP_LENGTH];
3014         VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
3015         InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
3016         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
3017 }
3018
3019 //============================================================================
3020
3021 // To create a almost working builtin file from this replace:
3022 // "^NULL.*" with ""
3023 // "^{.*//.*}:Wh\(.*\)" with "\1"
3024 // "\:" with "//"
3025 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
3026 // "\n\n+" with "\n\n"
3027
3028 prvm_builtin_t vm_cl_builtins[] = {
3029 NULL,                                                   // #0 NULL function (not callable) (QUAKE)
3030 VM_CL_makevectors,                              // #1 void(vector ang) makevectors (QUAKE)
3031 VM_CL_setorigin,                                // #2 void(entity e, vector o) setorigin (QUAKE)
3032 VM_CL_setmodel,                                 // #3 void(entity e, string m) setmodel (QUAKE)
3033 VM_CL_setsize,                                  // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3034 NULL,                                                   // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3035 VM_break,                                               // #6 void() break (QUAKE)
3036 VM_random,                                              // #7 float() random (QUAKE)
3037 VM_CL_sound,                                    // #8 void(entity e, float chan, string samp) sound (QUAKE)
3038 VM_normalize,                                   // #9 vector(vector v) normalize (QUAKE)
3039 VM_error,                                               // #10 void(string e) error (QUAKE)
3040 VM_objerror,                                    // #11 void(string e) objerror (QUAKE)
3041 VM_vlen,                                                // #12 float(vector v) vlen (QUAKE)
3042 VM_vectoyaw,                                    // #13 float(vector v) vectoyaw (QUAKE)
3043 VM_CL_spawn,                                    // #14 entity() spawn (QUAKE)
3044 VM_remove,                                              // #15 void(entity e) remove (QUAKE)
3045 VM_CL_traceline,                                // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
3046 NULL,                                                   // #17 entity() checkclient (QUAKE)
3047 VM_find,                                                // #18 entity(entity start, .string fld, string match) find (QUAKE)
3048 VM_precache_sound,                              // #19 void(string s) precache_sound (QUAKE)
3049 VM_CL_precache_model,                   // #20 void(string s) precache_model (QUAKE)
3050 NULL,                                                   // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3051 VM_CL_findradius,                               // #22 entity(vector org, float rad) findradius (QUAKE)
3052 NULL,                                                   // #23 void(string s, ...) bprint (QUAKE)
3053 NULL,                                                   // #24 void(entity client, string s, ...) sprint (QUAKE)
3054 VM_dprint,                                              // #25 void(string s, ...) dprint (QUAKE)
3055 VM_ftos,                                                // #26 string(float f) ftos (QUAKE)
3056 VM_vtos,                                                // #27 string(vector v) vtos (QUAKE)
3057 VM_coredump,                                    // #28 void() coredump (QUAKE)
3058 VM_traceon,                                             // #29 void() traceon (QUAKE)
3059 VM_traceoff,                                    // #30 void() traceoff (QUAKE)
3060 VM_eprint,                                              // #31 void(entity e) eprint (QUAKE)
3061 VM_CL_walkmove,                                 // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
3062 NULL,                                                   // #33 (QUAKE)
3063 VM_CL_droptofloor,                              // #34 float() droptofloor (QUAKE)
3064 VM_CL_lightstyle,                               // #35 void(float style, string value) lightstyle (QUAKE)
3065 VM_rint,                                                // #36 float(float v) rint (QUAKE)
3066 VM_floor,                                               // #37 float(float v) floor (QUAKE)
3067 VM_ceil,                                                // #38 float(float v) ceil (QUAKE)
3068 NULL,                                                   // #39 (QUAKE)
3069 VM_CL_checkbottom,                              // #40 float(entity e) checkbottom (QUAKE)
3070 VM_CL_pointcontents,                    // #41 float(vector v) pointcontents (QUAKE)
3071 NULL,                                                   // #42 (QUAKE)
3072 VM_fabs,                                                // #43 float(float f) fabs (QUAKE)
3073 NULL,                                                   // #44 vector(entity e, float speed) aim (QUAKE)
3074 VM_cvar,                                                // #45 float(string s) cvar (QUAKE)
3075 VM_localcmd,                                    // #46 void(string s) localcmd (QUAKE)
3076 VM_nextent,                                             // #47 entity(entity e) nextent (QUAKE)
3077 VM_CL_particle,                                 // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3078 VM_changeyaw,                                   // #49 void() ChangeYaw (QUAKE)
3079 NULL,                                                   // #50 (QUAKE)
3080 VM_vectoangles,                                 // #51 vector(vector v) vectoangles (QUAKE)
3081 NULL,                                                   // #52 void(float to, float f) WriteByte (QUAKE)
3082 NULL,                                                   // #53 void(float to, float f) WriteChar (QUAKE)
3083 NULL,                                                   // #54 void(float to, float f) WriteShort (QUAKE)
3084 NULL,                                                   // #55 void(float to, float f) WriteLong (QUAKE)
3085 NULL,                                                   // #56 void(float to, float f) WriteCoord (QUAKE)
3086 NULL,                                                   // #57 void(float to, float f) WriteAngle (QUAKE)
3087 NULL,                                                   // #58 void(float to, string s) WriteString (QUAKE)
3088 NULL,                                                   // #59 (QUAKE)
3089 VM_sin,                                                 // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3090 VM_cos,                                                 // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3091 VM_sqrt,                                                // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3092 VM_changepitch,                                 // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3093 VM_CL_tracetoss,                                // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3094 VM_etos,                                                // #65 string(entity ent) etos (DP_QC_ETOS)
3095 NULL,                                                   // #66 (QUAKE)
3096 NULL,                                                   // #67 void(float step) movetogoal (QUAKE)
3097 VM_precache_file,                               // #68 string(string s) precache_file (QUAKE)
3098 VM_CL_makestatic,                               // #69 void(entity e) makestatic (QUAKE)
3099 NULL,                                                   // #70 void(string s) changelevel (QUAKE)
3100 NULL,                                                   // #71 (QUAKE)
3101 VM_cvar_set,                                    // #72 void(string var, string val) cvar_set (QUAKE)
3102 NULL,                                                   // #73 void(entity client, strings) centerprint (QUAKE)
3103 VM_CL_ambientsound,                             // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3104 VM_CL_precache_model,                   // #75 string(string s) precache_model2 (QUAKE)
3105 VM_precache_sound,                              // #76 string(string s) precache_sound2 (QUAKE)
3106 VM_precache_file,                               // #77 string(string s) precache_file2 (QUAKE)
3107 NULL,                                                   // #78 void(entity e) setspawnparms (QUAKE)
3108 NULL,                                                   // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3109 NULL,                                                   // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3110 VM_stof,                                                // #81 float(string s) stof (FRIK_FILE)
3111 NULL,                                                   // #82 void(vector where, float set) multicast (QUAKEWORLD)
3112 NULL,                                                   // #83 (QUAKE)
3113 NULL,                                                   // #84 (QUAKE)
3114 NULL,                                                   // #85 (QUAKE)
3115 NULL,                                                   // #86 (QUAKE)
3116 NULL,                                                   // #87 (QUAKE)
3117 NULL,                                                   // #88 (QUAKE)
3118 NULL,                                                   // #89 (QUAKE)
3119 VM_CL_tracebox,                                 // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3120 VM_randomvec,                                   // #91 vector() randomvec (DP_QC_RANDOMVEC)
3121 VM_CL_getlight,                                 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3122 VM_registercvar,                                // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3123 VM_min,                                                 // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3124 VM_max,                                                 // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3125 VM_bound,                                               // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3126 VM_pow,                                                 // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3127 VM_findfloat,                                   // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3128 VM_checkextension,                              // #99 float(string s) checkextension (the basis of the extension system)
3129 // FrikaC and Telejano range #100-#199
3130 NULL,                                                   // #100
3131 NULL,                                                   // #101
3132 NULL,                                                   // #102
3133 NULL,                                                   // #103
3134 NULL,                                                   // #104
3135 NULL,                                                   // #105
3136 NULL,                                                   // #106
3137 NULL,                                                   // #107
3138 NULL,                                                   // #108
3139 NULL,                                                   // #109
3140 VM_fopen,                                               // #110 float(string filename, float mode) fopen (FRIK_FILE)
3141 VM_fclose,                                              // #111 void(float fhandle) fclose (FRIK_FILE)
3142 VM_fgets,                                               // #112 string(float fhandle) fgets (FRIK_FILE)
3143 VM_fputs,                                               // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3144 VM_strlen,                                              // #114 float(string s) strlen (FRIK_FILE)
3145 VM_strcat,                                              // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3146 VM_substring,                                   // #116 string(string s, float start, float length) substring (FRIK_FILE)
3147 VM_stov,                                                // #117 vector(string) stov (FRIK_FILE)
3148 VM_strzone,                                             // #118 string(string s) strzone (FRIK_FILE)
3149 VM_strunzone,                                   // #119 void(string s) strunzone (FRIK_FILE)
3150 NULL,                                                   // #120
3151 NULL,                                                   // #121
3152 NULL,                                                   // #122
3153 NULL,                                                   // #123
3154 NULL,                                                   // #124
3155 NULL,                                                   // #125
3156 NULL,                                                   // #126
3157 NULL,                                                   // #127
3158 NULL,                                                   // #128
3159 NULL,                                                   // #129
3160 NULL,                                                   // #130
3161 NULL,                                                   // #131
3162 NULL,                                                   // #132
3163 NULL,                                                   // #133
3164 NULL,                                                   // #134
3165 NULL,                                                   // #135
3166 NULL,                                                   // #136
3167 NULL,                                                   // #137
3168 NULL,                                                   // #138
3169 NULL,                                                   // #139
3170 NULL,                                                   // #140
3171 NULL,                                                   // #141
3172 NULL,                                                   // #142
3173 NULL,                                                   // #143
3174 NULL,                                                   // #144
3175 NULL,                                                   // #145
3176 NULL,                                                   // #146
3177 NULL,                                                   // #147
3178 NULL,                                                   // #148
3179 NULL,                                                   // #149
3180 NULL,                                                   // #150
3181 NULL,                                                   // #151
3182 NULL,                                                   // #152
3183 NULL,                                                   // #153
3184 NULL,                                                   // #154
3185 NULL,                                                   // #155
3186 NULL,                                                   // #156
3187 NULL,                                                   // #157
3188 NULL,                                                   // #158
3189 NULL,                                                   // #159
3190 NULL,                                                   // #160
3191 NULL,                                                   // #161
3192 NULL,                                                   // #162
3193 NULL,                                                   // #163
3194 NULL,                                                   // #164
3195 NULL,                                                   // #165
3196 NULL,                                                   // #166
3197 NULL,                                                   // #167
3198 NULL,                                                   // #168
3199 NULL,                                                   // #169
3200 NULL,                                                   // #170
3201 NULL,                                                   // #171
3202 NULL,                                                   // #172
3203 NULL,                                                   // #173
3204 NULL,                                                   // #174
3205 NULL,                                                   // #175
3206 NULL,                                                   // #176
3207 NULL,                                                   // #177
3208 NULL,                                                   // #178
3209 NULL,                                                   // #179
3210 NULL,                                                   // #180
3211 NULL,                                                   // #181
3212 NULL,                                                   // #182
3213 NULL,                                                   // #183
3214 NULL,                                                   // #184
3215 NULL,                                                   // #185
3216 NULL,                                                   // #186
3217 NULL,                                                   // #187
3218 NULL,                                                   // #188
3219 NULL,                                                   // #189
3220 NULL,                                                   // #190
3221 NULL,                                                   // #191
3222 NULL,                                                   // #192
3223 NULL,                                                   // #193
3224 NULL,                                                   // #194
3225 NULL,                                                   // #195
3226 NULL,                                                   // #196
3227 NULL,                                                   // #197
3228 NULL,                                                   // #198
3229 NULL,                                                   // #199
3230 // FTEQW range #200-#299
3231 NULL,                                                   // #200
3232 NULL,                                                   // #201
3233 NULL,                                                   // #202
3234 NULL,                                                   // #203
3235 NULL,                                                   // #204
3236 NULL,                                                   // #205
3237 NULL,                                                   // #206
3238 NULL,                                                   // #207
3239 NULL,                                                   // #208
3240 NULL,                                                   // #209
3241 NULL,                                                   // #210
3242 NULL,                                                   // #211
3243 NULL,                                                   // #212
3244 NULL,                                                   // #213
3245 NULL,                                                   // #214
3246 NULL,                                                   // #215
3247 NULL,                                                   // #216
3248 NULL,                                                   // #217
3249 VM_bitshift,                                    // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3250 NULL,                                                   // #219
3251 NULL,                                                   // #220
3252 VM_strstrofs,                                   // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3253 VM_str2chr,                                             // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3254 VM_chr2str,                                             // #223 string(float c, ...) chr2str (FTE_STRINGS)
3255 VM_strconv,                                             // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3256 VM_strpad,                                              // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3257 VM_infoadd,                                             // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3258 VM_infoget,                                             // #227 string(string info, string key) infoget (FTE_STRINGS)
3259 VM_strncmp,                                             // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3260 VM_strncasecmp,                                 // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3261 VM_strncasecmp,                                 // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3262 NULL,                                                   // #231
3263 NULL,                                                   // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3264 NULL,                                                   // #233
3265 NULL,                                                   // #234
3266 NULL,                                                   // #235
3267 NULL,                                                   // #236
3268 NULL,                                                   // #237
3269 NULL,                                                   // #238
3270 NULL,                                                   // #239
3271 NULL,                                                   // #240
3272 NULL,                                                   // #241
3273 NULL,                                                   // #242
3274 NULL,                                                   // #243
3275 NULL,                                                   // #244
3276 NULL,                                                   // #245
3277 NULL,                                                   // #246
3278 NULL,                                                   // #247
3279 NULL,                                                   // #248
3280 NULL,                                                   // #249
3281 NULL,                                                   // #250
3282 NULL,                                                   // #251
3283 NULL,                                                   // #252
3284 NULL,                                                   // #253
3285 NULL,                                                   // #254
3286 NULL,                                                   // #255
3287 NULL,                                                   // #256
3288 NULL,                                                   // #257
3289 NULL,                                                   // #258
3290 NULL,                                                   // #259
3291 NULL,                                                   // #260
3292 NULL,                                                   // #261
3293 NULL,                                                   // #262
3294 NULL,                                                   // #263
3295 NULL,                                                   // #264
3296 NULL,                                                   // #265
3297 NULL,                                                   // #266
3298 NULL,                                                   // #267
3299 NULL,                                                   // #268
3300 NULL,                                                   // #269
3301 NULL,                                                   // #270
3302 NULL,                                                   // #271
3303 NULL,                                                   // #272
3304 NULL,                                                   // #273
3305 NULL,                                                   // #274
3306 NULL,                                                   // #275
3307 NULL,                                                   // #276
3308 NULL,                                                   // #277
3309 NULL,                                                   // #278
3310 NULL,                                                   // #279
3311 NULL,                                                   // #280
3312 NULL,                                                   // #281
3313 NULL,                                                   // #282
3314 NULL,                                                   // #283
3315 NULL,                                                   // #284
3316 NULL,                                                   // #285
3317 NULL,                                                   // #286
3318 NULL,                                                   // #287
3319 NULL,                                                   // #288
3320 NULL,                                                   // #289
3321 NULL,                                                   // #290
3322 NULL,                                                   // #291
3323 NULL,                                                   // #292
3324 NULL,                                                   // #293
3325 NULL,                                                   // #294
3326 NULL,                                                   // #295
3327 NULL,                                                   // #296
3328 NULL,                                                   // #297
3329 NULL,                                                   // #298
3330 NULL,                                                   // #299
3331 // CSQC range #300-#399
3332 VM_CL_R_ClearScene,                             // #300 void() clearscene (EXT_CSQC)
3333 VM_CL_R_AddEntities,                    // #301 void(float mask) addentities (EXT_CSQC)
3334 VM_CL_R_AddEntity,                              // #302 void(entity ent) addentity (EXT_CSQC)
3335 VM_CL_R_SetView,                                // #303 float(float property, ...) setproperty (EXT_CSQC)
3336 VM_CL_R_RenderScene,                    // #304 void() renderscene (EXT_CSQC)
3337 VM_CL_R_AddDynamicLight,                // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3338 VM_CL_R_PolygonBegin,                   // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3339 VM_CL_R_PolygonVertex,                  // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3340 VM_CL_R_PolygonEnd,                             // #308 void() R_EndPolygon
3341 NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
3342 VM_CL_unproject,                                // #310 vector (vector v) cs_unproject (EXT_CSQC)
3343 VM_CL_project,                                  // #311 vector (vector v) cs_project (EXT_CSQC)
3344 NULL,                                                   // #312
3345 NULL,                                                   // #313
3346 NULL,                                                   // #314
3347 VM_drawline,                                    // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3348 VM_iscachedpic,                                 // #316 float(string name) iscachedpic (EXT_CSQC)
3349 VM_precache_pic,                                // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3350 VM_getimagesize,                                // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3351 VM_freepic,                                             // #319 void(string name) freepic (EXT_CSQC)
3352 VM_drawcharacter,                               // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3353 VM_drawstring,                                  // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3354 VM_drawpic,                                             // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3355 VM_drawfill,                                    // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3356 VM_drawsetcliparea,                             // #324 void(float x, float y, float width, float height) drawsetcliparea
3357 VM_drawresetcliparea,                   // #325 void(void) drawresetcliparea
3358 VM_drawcolorcodedstring,                // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3359 VM_stringwidth,                 // #327 // FIXME is this okay?
3360 VM_drawsubpic,                                  // #328 // FIXME is this okay?
3361 NULL,                                                   // #329
3362 VM_CL_getstatf,                                 // #330 float(float stnum) getstatf (EXT_CSQC)
3363 VM_CL_getstati,                                 // #331 float(float stnum) getstati (EXT_CSQC)
3364 VM_CL_getstats,                                 // #332 string(float firststnum) getstats (EXT_CSQC)
3365 VM_CL_setmodelindex,                    // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3366 VM_CL_modelnameforindex,                // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3367 VM_CL_particleeffectnum,                // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3368 VM_CL_trailparticles,                   // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3369 VM_CL_pointparticles,                   // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3370 VM_centerprint,                                 // #338 void(string s, ...) centerprint (EXT_CSQC)
3371 VM_print,                                               // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3372 VM_keynumtostring,                              // #340 string(float keynum) keynumtostring (EXT_CSQC)
3373 VM_stringtokeynum,                              // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3374 VM_CL_getkeybind,                               // #342 string(float keynum) getkeybind (EXT_CSQC)
3375 VM_CL_setcursormode,                    // #343 void(float usecursor) setcursormode (EXT_CSQC)
3376 VM_CL_getmousepos,                              // #344 vector() getmousepos (EXT_CSQC)
3377 VM_CL_getinputstate,                    // #345 float(float framenum) getinputstate (EXT_CSQC)
3378 VM_CL_setsensitivityscale,              // #346 void(float sens) setsensitivityscale (EXT_CSQC)
3379 VM_CL_runplayerphysics,                 // #347 void() runstandardplayerphysics (EXT_CSQC)
3380 VM_CL_getplayerkey,                             // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3381 VM_CL_isdemo,                                   // #349 float() isdemo (EXT_CSQC)
3382 VM_isserver,                                    // #350 float() isserver (EXT_CSQC)
3383 VM_CL_setlistener,                              // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3384 VM_CL_registercmd,                              // #352 void(string cmdname) registercommand (EXT_CSQC)
3385 VM_wasfreed,                                    // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3386 VM_CL_serverkey,                                // #354 string(string key) serverkey (EXT_CSQC)
3387 NULL,                                                   // #355
3388 NULL,                                                   // #356
3389 NULL,                                                   // #357
3390 NULL,                                                   // #358
3391 NULL,                                                   // #359
3392 VM_CL_ReadByte,                                 // #360 float() readbyte (EXT_CSQC)
3393 VM_CL_ReadChar,                                 // #361 float() readchar (EXT_CSQC)
3394 VM_CL_ReadShort,                                // #362 float() readshort (EXT_CSQC)
3395 VM_CL_ReadLong,                                 // #363 float() readlong (EXT_CSQC)
3396 VM_CL_ReadCoord,                                // #364 float() readcoord (EXT_CSQC)
3397 VM_CL_ReadAngle,                                // #365 float() readangle (EXT_CSQC)
3398 VM_CL_ReadString,                               // #366 string() readstring (EXT_CSQC)
3399 VM_CL_ReadFloat,                                // #367 float() readfloat (EXT_CSQC)
3400 NULL,                                           // #368
3401 NULL,                                                   // #369
3402 NULL,                                                   // #370
3403 NULL,                                                   // #371
3404 NULL,                                                   // #372
3405 NULL,                                                   // #373
3406 NULL,                                                   // #374
3407 NULL,                                                   // #375
3408 NULL,                                                   // #376
3409 NULL,                                                   // #377
3410 NULL,                                                   // #378
3411 NULL,                                                   // #379
3412 NULL,                                                   // #380
3413 NULL,                                                   // #381
3414 NULL,                                                   // #382
3415 NULL,                                                   // #383
3416 NULL,                                                   // #384
3417 NULL,                                                   // #385
3418 NULL,                                                   // #386
3419 NULL,                                                   // #387
3420 NULL,                                                   // #388
3421 NULL,                                                   // #389
3422 NULL,                                                   // #390
3423 NULL,                                                   // #391
3424 NULL,                                                   // #392
3425 NULL,                                                   // #393
3426 NULL,                                                   // #394
3427 NULL,                                                   // #395
3428 NULL,                                                   // #396
3429 NULL,                                                   // #397
3430 NULL,                                                   // #398
3431 NULL,                                                   // #399
3432 // LordHavoc's range #400-#499
3433 VM_CL_copyentity,                               // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3434 NULL,                                                   // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3435 VM_findchain,                                   // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3436 VM_findchainfloat,                              // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3437 VM_CL_effect,                                   // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3438 VM_CL_te_blood,                                 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3439 VM_CL_te_bloodshower,                   // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3440 VM_CL_te_explosionrgb,                  // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3441 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)
3442 VM_CL_te_particlerain,                  // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3443 VM_CL_te_particlesnow,                  // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3444 VM_CL_te_spark,                                 // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3445 VM_CL_te_gunshotquad,                   // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3446 VM_CL_te_spikequad,                             // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3447 VM_CL_te_superspikequad,                // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3448 VM_CL_te_explosionquad,                 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3449 VM_CL_te_smallflash,                    // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3450 VM_CL_te_customflash,                   // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3451 VM_CL_te_gunshot,                               // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3452 VM_CL_te_spike,                                 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3453 VM_CL_te_superspike,                    // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3454 VM_CL_te_explosion,                             // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3455 VM_CL_te_tarexplosion,                  // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3456 VM_CL_te_wizspike,                              // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3457 VM_CL_te_knightspike,                   // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3458 VM_CL_te_lavasplash,                    // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3459 VM_CL_te_teleport,                              // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3460 VM_CL_te_explosion2,                    // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3461 VM_CL_te_lightning1,                    // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3462 VM_CL_te_lightning2,                    // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3463 VM_CL_te_lightning3,                    // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3464 VM_CL_te_beam,                                  // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3465 VM_vectorvectors,                               // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3466 VM_CL_te_plasmaburn,                    // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3467 VM_CL_getsurfacenumpoints,              // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3468 VM_CL_getsurfacepoint,                  // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3469 VM_CL_getsurfacenormal,                 // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3470 VM_CL_getsurfacetexture,                // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3471 VM_CL_getsurfacenearpoint,              // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3472 VM_CL_getsurfaceclippedpoint,   // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3473 NULL,                                                   // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3474 VM_tokenize,                                    // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3475 VM_argv,                                                // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3476 VM_CL_setattachment,                    // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3477 VM_search_begin,                                // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3478 VM_search_end,                                  // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3479 VM_search_getsize,                              // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3480 VM_search_getfilename,                  // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3481 VM_cvar_string,                                 // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3482 VM_findflags,                                   // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3483 VM_findchainflags,                              // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3484 VM_CL_gettagindex,                              // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3485 VM_CL_gettaginfo,                               // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3486 NULL,                                                   // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3487 NULL,                                                   // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3488 NULL,                                                   // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3489 NULL,                                                   // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3490 VM_CL_te_flamejet,                              // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
3491 NULL,                                                   // #458
3492 VM_ftoe,                                                // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3493 VM_buf_create,                                  // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3494 VM_buf_del,                                             // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3495 VM_buf_getsize,                                 // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3496 VM_buf_copy,                                    // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3497 VM_buf_sort,                                    // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3498 VM_buf_implode,                                 // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3499 VM_bufstr_get,                                  // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3500 VM_bufstr_set,                                  // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3501 VM_bufstr_add,                                  // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3502 VM_bufstr_free,                                 // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3503 NULL,                                                   // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3504 VM_asin,                                                // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3505 VM_acos,                                                // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3506 VM_atan,                                                // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3507 VM_atan2,                                               // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3508 VM_tan,                                                 // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3509 VM_strlennocol,                                 // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3510 VM_strdecolorize,                               // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3511 VM_strftime,                                    // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3512 VM_tokenizebyseparator,                 // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3513 VM_strtolower,                                  // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3514 VM_strtoupper,                                  // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3515 VM_cvar_defstring,                              // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3516 VM_CL_pointsound,                               // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
3517 VM_strreplace,                                  // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3518 VM_strireplace,                                 // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3519 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
3520 VM_gecko_create,                                        // #487 float gecko_create( string name )
3521 VM_gecko_destroy,                                       // #488 void gecko_destroy( string name )
3522 VM_gecko_navigate,                              // #489 void gecko_navigate( string name, string URI )
3523 VM_gecko_keyevent,                              // #490 float gecko_keyevent( string name, float key, float eventtype )
3524 VM_gecko_movemouse,                             // #491 void gecko_mousemove( string name, float x, float y )
3525 VM_gecko_resize,                                        // #492 void gecko_resize( string name, float w, float h )
3526 VM_gecko_get_texture_extent,    // #493 vector gecko_get_texture_extent( string name )
3527 VM_crc16,                                               // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3528 VM_cvar_type,                                   // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3529 VM_numentityfields,                             // #496 float() numentityfields = #496; (QP_QC_ENTITYDATA)
3530 VM_entityfieldname,                             // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3531 VM_entityfieldtype,                             // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3532 VM_getentityfieldstring,                // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3533 VM_putentityfieldstring,                // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3534 VM_CL_ReadPicture,                              // #501 string() ReadPicture = #501;
3535 NULL,                                                   // #502
3536 VM_whichpack,                                   // #503 string(string) whichpack = #503;
3537 NULL,                                                   // #504
3538 NULL,                                                   // #505
3539 NULL,                                                   // #506
3540 NULL,                                                   // #507
3541 NULL,                                                   // #508
3542 NULL,                                                   // #509
3543 VM_uri_escape,                                  // #510 string(string in) uri_escape = #510;
3544 VM_uri_unescape,                                // #511 string(string in) uri_unescape = #511;
3545 VM_etof,                                        // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3546 VM_uri_get,                                             // #513 float(string uril, float id) uri_get = #512; (DP_QC_URI_GET)
3547 VM_tokenize_console,                                    // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3548 VM_argv_start_index,                                    // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3549 VM_argv_end_index,                                              // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3550 VM_buf_cvarlist,                                                // #517 void(float buf, string prefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3551 VM_cvar_description,                                    // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3552 NULL,                                                   // #519
3553 VM_keynumtostring,                              // #520 string keynumtostring(float keynum)
3554 VM_findkeysforcommand,          // #521 string findkeysforcommand(string command)
3555 };
3556
3557 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3558
3559 void VM_Polygons_Reset(void)
3560 {
3561         vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
3562
3563         // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3564         if(polys->initialized)
3565         {
3566                 Mem_FreePool(&polys->pool);
3567                 polys->initialized = false;
3568         }
3569 }
3570
3571 void VM_CL_Cmd_Init(void)
3572 {
3573         VM_Cmd_Init();
3574         VM_Polygons_Reset();
3575 }
3576
3577 void VM_CL_Cmd_Reset(void)
3578 {
3579         VM_Cmd_Reset();
3580         VM_Polygons_Reset();
3581 }
3582
3583