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