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