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