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