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