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