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