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