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