]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
added an easteregg (v_psycho), thanks to Zinx Verituse and Ben Winslow for the origin...
[divverent/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
25
26 mempool_t *pr_strings_mempool;
27
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
33
34 static char *PR_GetTempString(void)
35 {
36         char *s;
37         s = pr_string_temp[pr_string_tempindex];
38         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
39         return s;
40 }
41
42 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
43
44
45 /*
46 ===============================================================================
47
48                                                 BUILT-IN FUNCTIONS
49
50 ===============================================================================
51 */
52
53
54 void PF_VarString(int first, char *out, int outlength)
55 {
56         int i;
57         const char *s;
58         char *outend;
59
60         outend = out + outlength - 1;
61         for (i = first;i < pr_argc && out < outend;i++)
62         {
63                 s = G_STRING((OFS_PARM0+i*3));
64                 while (out < outend && *s)
65                         *out++ = *s++;
66         }
67         *out++ = 0;
68 }
69
70 char *ENGINE_EXTENSIONS =
71 "DP_CL_LOADSKY "
72 "DP_EF_NODRAW "
73 "DP_EF_ADDITIVE "
74 "DP_EF_BLUE "
75 "DP_EF_RED "
76 "DP_EF_FULLBRIGHT "
77 "DP_EF_FLAME "
78 "DP_EF_STARDUST "
79 "DP_ENT_ALPHA "
80 "DP_ENT_CUSTOMCOLORMAP "
81 "DP_ENT_EXTERIORMODELTOCLIENT "
82 "DP_ENT_LOWPRECISION "
83 "DP_ENT_GLOW "
84 "DP_ENT_SCALE "
85 "DP_ENT_VIEWMODEL "
86 "DP_GFX_EXTERNALTEXTURES "
87 "DP_GFX_FOG "
88 "DP_GFX_QUAKE3MODELTAGS "
89 "DP_GFX_SKINFILES "
90 "DP_GFX_SKYBOX "
91 "DP_HALFLIFE_MAP "
92 "DP_HALFLIFE_MAP_CVAR "
93 "DP_INPUTBUTTONS "
94 "DP_LITSUPPORT "
95 "DP_MONSTERWALK "
96 "DP_MOVETYPEBOUNCEMISSILE "
97 "DP_MOVETYPEFOLLOW "
98 "DP_QC_CHANGEPITCH "
99 "DP_QC_COPYENTITY "
100 "DP_QC_ETOS "
101 "DP_QC_FINDCHAIN "
102 "DP_QC_FINDCHAINFLOAT "
103 "DP_QC_FINDFLOAT "
104 "DP_QC_GETLIGHT "
105 "DP_QC_GETSURFACE "
106 "DP_QC_MINMAXBOUND "
107 "DP_QC_RANDOMVEC "
108 "DP_QC_SINCOSSQRTPOW "
109 "DP_QC_TRACEBOX "
110 "DP_QC_TRACETOSS "
111 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
112 "DP_QC_TRACE_MOVETYPE_HITMODEL "
113 "DP_QC_VECTORVECTORS "
114 "DP_QUAKE2_MODEL "
115 "DP_QUAKE3_MODEL "
116 "DP_REGISTERCVAR "
117 "DP_SOLIDCORPSE "
118 "DP_SPRITE32 "
119 "DP_SV_DRAWONLYTOCLIENT "
120 "DP_SV_EFFECT "
121 "DP_SV_EXTERIORMODELTOCLIENT "
122 "DP_SV_NODRAWTOCLIENT "
123 "DP_SV_PLAYERPHYSICS "
124 "DP_SV_SETCOLOR "
125 "DP_SV_SLOWMO "
126 "DP_TE_BLOOD "
127 "DP_TE_BLOODSHOWER "
128 "DP_TE_CUSTOMFLASH "
129 "DP_TE_EXPLOSIONRGB "
130 "DP_TE_FLAMEJET "
131 "DP_TE_PARTICLECUBE "
132 "DP_TE_PARTICLERAIN "
133 "DP_TE_PARTICLESNOW "
134 "DP_TE_PLASMABURN "
135 "DP_TE_QUADEFFECTS1 "
136 "DP_TE_SMALLFLASH "
137 "DP_TE_SPARK "
138 "DP_TE_STANDARDEFFECTBUILTINS "
139 "DP_VIEWZOOM "
140 "FRIK_FILE "
141 "KRIMZON_SV_PARSECLIENTCOMMAND "
142 "NEH_CMD_PLAY2 "
143 "NEH_RESTOREGAME "
144 "TW_SV_STEPCONTROL "
145 ;
146
147 qboolean checkextension(char *name)
148 {
149         int len;
150         char *e, *start;
151         len = strlen(name);
152         for (e = ENGINE_EXTENSIONS;*e;e++)
153         {
154                 while (*e == ' ')
155                         e++;
156                 if (!*e)
157                         break;
158                 start = e;
159                 while (*e && *e != ' ')
160                         e++;
161                 if (e - start == len)
162                         if (!strncasecmp(start, name, len))
163                                 return true;
164         }
165         return false;
166 }
167
168 /*
169 =================
170 PF_checkextension
171
172 returns true if the extension is supported by the server
173
174 checkextension(extensionname)
175 =================
176 */
177 void PF_checkextension (void)
178 {
179         G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
180 }
181
182 /*
183 =================
184 PF_error
185
186 This is a TERMINAL error, which will kill off the entire server.
187 Dumps self.
188
189 error(value)
190 =================
191 */
192 void PF_error (void)
193 {
194         edict_t *ed;
195         char string[STRINGTEMP_LENGTH];
196
197         PF_VarString(0, string, sizeof(string));
198         Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
199         ed = PROG_TO_EDICT(pr_global_struct->self);
200         ED_Print (ed);
201
202         Host_Error ("Program error");
203 }
204
205 /*
206 =================
207 PF_objerror
208
209 Dumps out self, then an error message.  The program is aborted and self is
210 removed, but the level can continue.
211
212 objerror(value)
213 =================
214 */
215 void PF_objerror (void)
216 {
217         edict_t *ed;
218         char string[STRINGTEMP_LENGTH];
219
220         PF_VarString(0, string, sizeof(string));
221         Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
222         ed = PROG_TO_EDICT(pr_global_struct->self);
223         ED_Print (ed);
224         ED_Free (ed);
225 }
226
227
228 /*
229 ==============
230 PF_makevectors
231
232 Writes new values for v_forward, v_up, and v_right based on angles
233 makevectors(vector)
234 ==============
235 */
236 void PF_makevectors (void)
237 {
238         AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
239 }
240
241 /*
242 ==============
243 PF_vectorvectors
244
245 Writes new values for v_forward, v_up, and v_right based on the given forward vector
246 vectorvectors(vector, vector)
247 ==============
248 */
249 void PF_vectorvectors (void)
250 {
251         VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
252         VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
253 }
254
255 /*
256 =================
257 PF_setorigin
258
259 This is the only valid way to move an object without using the physics of the world (setting velocity and waiting).  Directly changing origin will not set internal links correctly, so clipping would be messed up.  This should be called when an object is spawned, and then only if it is teleported.
260
261 setorigin (entity, origin)
262 =================
263 */
264 void PF_setorigin (void)
265 {
266         edict_t *e;
267         float   *org;
268
269         e = G_EDICT(OFS_PARM0);
270         if (e == sv.edicts)
271                 Host_Error("setorigin: can not modify world entity\n");
272         if (e->e->free)
273                 Host_Error("setorigin: can not modify free entity\n");
274         org = G_VECTOR(OFS_PARM1);
275         VectorCopy (org, e->v->origin);
276         SV_LinkEdict (e, false);
277 }
278
279
280 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
281 {
282         int             i;
283
284         for (i=0 ; i<3 ; i++)
285                 if (min[i] > max[i])
286                         Host_Error ("backwards mins/maxs");
287
288 // set derived values
289         VectorCopy (min, e->v->mins);
290         VectorCopy (max, e->v->maxs);
291         VectorSubtract (max, min, e->v->size);
292
293         SV_LinkEdict (e, false);
294 }
295
296 /*
297 =================
298 PF_setsize
299
300 the size box is rotated by the current angle
301 LordHavoc: no it isn't...
302
303 setsize (entity, minvector, maxvector)
304 =================
305 */
306 void PF_setsize (void)
307 {
308         edict_t *e;
309         float   *min, *max;
310
311         e = G_EDICT(OFS_PARM0);
312         if (e == sv.edicts)
313                 Host_Error("setsize: can not modify world entity\n");
314         if (e->e->free)
315                 Host_Error("setsize: can not modify free entity\n");
316         min = G_VECTOR(OFS_PARM1);
317         max = G_VECTOR(OFS_PARM2);
318         SetMinMaxSize (e, min, max, false);
319 }
320
321
322 /*
323 =================
324 PF_setmodel
325
326 setmodel(entity, model)
327 =================
328 */
329 void PF_setmodel (void)
330 {
331         edict_t *e;
332         char    *m, **check;
333         model_t *mod;
334         int             i;
335
336         e = G_EDICT(OFS_PARM0);
337         if (e == sv.edicts)
338                 Host_Error("setmodel: can not modify world entity\n");
339         if (e->e->free)
340                 Host_Error("setmodel: can not modify free entity\n");
341         m = G_STRING(OFS_PARM1);
342
343 // check to see if model was properly precached
344         for (i=0, check = sv.model_precache ; *check ; i++, check++)
345                 if (!strcmp(*check, m))
346                         break;
347
348         if (!*check)
349                 Host_Error ("no precache: %s\n", m);
350
351
352         e->v->model = PR_SetString(*check);
353         e->v->modelindex = i;
354
355         mod = sv.models[ (int)e->v->modelindex];
356
357         if (mod)
358                 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
359         else
360                 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
361 }
362
363 /*
364 =================
365 PF_bprint
366
367 broadcast print to everyone on server
368
369 bprint(value)
370 =================
371 */
372 void PF_bprint (void)
373 {
374         char string[STRINGTEMP_LENGTH];
375         PF_VarString(0, string, sizeof(string));
376         SV_BroadcastPrintf("%s", string);
377 }
378
379 /*
380 =================
381 PF_sprint
382
383 single print to a specific client
384
385 sprint(clientent, value)
386 =================
387 */
388 void PF_sprint (void)
389 {
390         client_t        *client;
391         int                     entnum;
392         char string[STRINGTEMP_LENGTH];
393
394         entnum = G_EDICTNUM(OFS_PARM0);
395
396         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
397         {
398                 Con_Printf ("tried to sprint to a non-client\n");
399                 return;
400         }
401
402         client = svs.clients + entnum-1;
403         if (!client->netconnection)
404                 return;
405         PF_VarString(1, string, sizeof(string));
406         MSG_WriteChar(&client->message,svc_print);
407         MSG_WriteString(&client->message, string);
408 }
409
410
411 /*
412 =================
413 PF_centerprint
414
415 single print to a specific client
416
417 centerprint(clientent, value)
418 =================
419 */
420 void PF_centerprint (void)
421 {
422         client_t        *client;
423         int                     entnum;
424         char string[STRINGTEMP_LENGTH];
425
426         entnum = G_EDICTNUM(OFS_PARM0);
427
428         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
429         {
430                 Con_Printf ("tried to sprint to a non-client\n");
431                 return;
432         }
433
434         client = svs.clients + entnum-1;
435         if (!client->netconnection)
436                 return;
437         PF_VarString(1, string, sizeof(string));
438         MSG_WriteChar(&client->message,svc_centerprint);
439         MSG_WriteString(&client->message, string);
440 }
441
442
443 /*
444 =================
445 PF_normalize
446
447 vector normalize(vector)
448 =================
449 */
450 void PF_normalize (void)
451 {
452         float   *value1;
453         vec3_t  newvalue;
454         float   new;
455
456         value1 = G_VECTOR(OFS_PARM0);
457
458         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
459         new = sqrt(new);
460
461         if (new == 0)
462                 newvalue[0] = newvalue[1] = newvalue[2] = 0;
463         else
464         {
465                 new = 1/new;
466                 newvalue[0] = value1[0] * new;
467                 newvalue[1] = value1[1] * new;
468                 newvalue[2] = value1[2] * new;
469         }
470
471         VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
472 }
473
474 /*
475 =================
476 PF_vlen
477
478 scalar vlen(vector)
479 =================
480 */
481 void PF_vlen (void)
482 {
483         float   *value1;
484         float   new;
485
486         value1 = G_VECTOR(OFS_PARM0);
487
488         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
489         new = sqrt(new);
490
491         G_FLOAT(OFS_RETURN) = new;
492 }
493
494 /*
495 =================
496 PF_vectoyaw
497
498 float vectoyaw(vector)
499 =================
500 */
501 void PF_vectoyaw (void)
502 {
503         float   *value1;
504         float   yaw;
505
506         value1 = G_VECTOR(OFS_PARM0);
507
508         if (value1[1] == 0 && value1[0] == 0)
509                 yaw = 0;
510         else
511         {
512                 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
513                 if (yaw < 0)
514                         yaw += 360;
515         }
516
517         G_FLOAT(OFS_RETURN) = yaw;
518 }
519
520
521 /*
522 =================
523 PF_vectoangles
524
525 vector vectoangles(vector)
526 =================
527 */
528 void PF_vectoangles (void)
529 {
530         float   *value1;
531         float   forward;
532         float   yaw, pitch;
533
534         value1 = G_VECTOR(OFS_PARM0);
535
536         if (value1[1] == 0 && value1[0] == 0)
537         {
538                 yaw = 0;
539                 if (value1[2] > 0)
540                         pitch = 90;
541                 else
542                         pitch = 270;
543         }
544         else
545         {
546                 // LordHavoc: optimized a bit
547                 if (value1[0])
548                 {
549                         yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
550                         if (yaw < 0)
551                                 yaw += 360;
552                 }
553                 else if (value1[1] > 0)
554                         yaw = 90;
555                 else
556                         yaw = 270;
557
558                 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
559                 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
560                 if (pitch < 0)
561                         pitch += 360;
562         }
563
564         G_FLOAT(OFS_RETURN+0) = pitch;
565         G_FLOAT(OFS_RETURN+1) = yaw;
566         G_FLOAT(OFS_RETURN+2) = 0;
567 }
568
569 /*
570 =================
571 PF_Random
572
573 Returns a number from 0<= num < 1
574
575 random()
576 =================
577 */
578 void PF_random (void)
579 {
580         float           num;
581
582         num = (rand ()&0x7fff) / ((float)0x7fff);
583
584         G_FLOAT(OFS_RETURN) = num;
585 }
586
587 /*
588 =================
589 PF_particle
590
591 particle(origin, color, count)
592 =================
593 */
594 void PF_particle (void)
595 {
596         float           *org, *dir;
597         float           color;
598         float           count;
599
600         org = G_VECTOR(OFS_PARM0);
601         dir = G_VECTOR(OFS_PARM1);
602         color = G_FLOAT(OFS_PARM2);
603         count = G_FLOAT(OFS_PARM3);
604         SV_StartParticle (org, dir, color, count);
605 }
606
607
608 /*
609 =================
610 PF_ambientsound
611
612 =================
613 */
614 void PF_ambientsound (void)
615 {
616         char            **check;
617         char            *samp;
618         float           *pos;
619         float           vol, attenuation;
620         int                     i, soundnum, large;
621
622         pos = G_VECTOR (OFS_PARM0);
623         samp = G_STRING(OFS_PARM1);
624         vol = G_FLOAT(OFS_PARM2);
625         attenuation = G_FLOAT(OFS_PARM3);
626
627 // check to see if samp was properly precached
628         for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
629                 if (!strcmp(*check,samp))
630                         break;
631
632         if (!*check)
633         {
634                 Con_Printf ("no precache: %s\n", samp);
635                 return;
636         }
637
638         large = false;
639         if (soundnum >= 256)
640                 large = true;
641
642         // add an svc_spawnambient command to the level signon packet
643
644         if (large)
645                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
646         else
647                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
648
649         for (i=0 ; i<3 ; i++)
650                 MSG_WriteDPCoord(&sv.signon, pos[i]);
651
652         if (large)
653                 MSG_WriteShort (&sv.signon, soundnum);
654         else
655                 MSG_WriteByte (&sv.signon, soundnum);
656
657         MSG_WriteByte (&sv.signon, vol*255);
658         MSG_WriteByte (&sv.signon, attenuation*64);
659
660 }
661
662 /*
663 =================
664 PF_sound
665
666 Each entity can have eight independant sound sources, like voice,
667 weapon, feet, etc.
668
669 Channel 0 is an auto-allocate channel, the others override anything
670 already running on that entity/channel pair.
671
672 An attenuation of 0 will play full volume everywhere in the level.
673 Larger attenuations will drop off.
674
675 =================
676 */
677 void PF_sound (void)
678 {
679         char            *sample;
680         int                     channel;
681         edict_t         *entity;
682         int             volume;
683         float attenuation;
684
685         entity = G_EDICT(OFS_PARM0);
686         channel = G_FLOAT(OFS_PARM1);
687         sample = G_STRING(OFS_PARM2);
688         volume = G_FLOAT(OFS_PARM3) * 255;
689         attenuation = G_FLOAT(OFS_PARM4);
690
691         if (volume < 0 || volume > 255)
692                 Host_Error ("SV_StartSound: volume = %i", volume);
693
694         if (attenuation < 0 || attenuation > 4)
695                 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
696
697         if (channel < 0 || channel > 7)
698                 Host_Error ("SV_StartSound: channel = %i", channel);
699
700         SV_StartSound (entity, channel, sample, volume, attenuation);
701 }
702
703 /*
704 =================
705 PF_break
706
707 break()
708 =================
709 */
710 void PF_break (void)
711 {
712         Host_Error ("break statement");
713 }
714
715 /*
716 =================
717 PF_traceline
718
719 Used for use tracing and shot targeting
720 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
721 if the tryents flag is set.
722
723 traceline (vector1, vector2, tryents)
724 =================
725 */
726 void PF_traceline (void)
727 {
728         float   *v1, *v2;
729         trace_t trace;
730         int             nomonsters;
731         edict_t *ent;
732
733         pr_xfunction->builtinsprofile += 30;
734
735         v1 = G_VECTOR(OFS_PARM0);
736         v2 = G_VECTOR(OFS_PARM1);
737         nomonsters = G_FLOAT(OFS_PARM2);
738         ent = G_EDICT(OFS_PARM3);
739
740         trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
741
742         pr_global_struct->trace_allsolid = trace.allsolid;
743         pr_global_struct->trace_startsolid = trace.startsolid;
744         pr_global_struct->trace_fraction = trace.fraction;
745         pr_global_struct->trace_inwater = trace.inwater;
746         pr_global_struct->trace_inopen = trace.inopen;
747         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
748         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
749         pr_global_struct->trace_plane_dist =  trace.plane.dist;
750         if (trace.ent)
751                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
752         else
753                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
754         // FIXME: add trace_endcontents
755 }
756
757
758 /*
759 =================
760 PF_tracebox
761
762 Used for use tracing and shot targeting
763 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
764 if the tryents flag is set.
765
766 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
767 =================
768 */
769 // LordHavoc: added this for my own use, VERY useful, similar to traceline
770 void PF_tracebox (void)
771 {
772         float   *v1, *v2, *m1, *m2;
773         trace_t trace;
774         int             nomonsters;
775         edict_t *ent;
776
777         pr_xfunction->builtinsprofile += 30;
778
779         v1 = G_VECTOR(OFS_PARM0);
780         m1 = G_VECTOR(OFS_PARM1);
781         m2 = G_VECTOR(OFS_PARM2);
782         v2 = G_VECTOR(OFS_PARM3);
783         nomonsters = G_FLOAT(OFS_PARM4);
784         ent = G_EDICT(OFS_PARM5);
785
786         trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
787
788         pr_global_struct->trace_allsolid = trace.allsolid;
789         pr_global_struct->trace_startsolid = trace.startsolid;
790         pr_global_struct->trace_fraction = trace.fraction;
791         pr_global_struct->trace_inwater = trace.inwater;
792         pr_global_struct->trace_inopen = trace.inopen;
793         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
794         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
795         pr_global_struct->trace_plane_dist =  trace.plane.dist;
796         if (trace.ent)
797                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
798         else
799                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
800 }
801
802 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
803 void PF_TraceToss (void)
804 {
805         trace_t trace;
806         edict_t *ent;
807         edict_t *ignore;
808
809         pr_xfunction->builtinsprofile += 600;
810
811         ent = G_EDICT(OFS_PARM0);
812         if (ent == sv.edicts)
813                 Host_Error("tracetoss: can not use world entity\n");
814         ignore = G_EDICT(OFS_PARM1);
815
816         trace = SV_Trace_Toss (ent, ignore);
817
818         pr_global_struct->trace_allsolid = trace.allsolid;
819         pr_global_struct->trace_startsolid = trace.startsolid;
820         pr_global_struct->trace_fraction = trace.fraction;
821         pr_global_struct->trace_inwater = trace.inwater;
822         pr_global_struct->trace_inopen = trace.inopen;
823         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
824         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
825         pr_global_struct->trace_plane_dist =  trace.plane.dist;
826         if (trace.ent)
827                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
828         else
829                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
830 }
831
832
833 /*
834 =================
835 PF_checkpos
836
837 Returns true if the given entity can move to the given position from it's
838 current position by walking or rolling.
839 FIXME: make work...
840 scalar checkpos (entity, vector)
841 =================
842 */
843 void PF_checkpos (void)
844 {
845 }
846
847 //============================================================================
848
849 int checkpvsbytes;
850 qbyte checkpvs[MAX_MAP_LEAFS/8];
851
852 int PF_newcheckclient (int check)
853 {
854         int             i;
855         edict_t *ent;
856         vec3_t  org;
857
858 // cycle to the next one
859
860         check = bound(1, check, svs.maxclients);
861         if (check == svs.maxclients)
862                 i = 1;
863         else
864                 i = check + 1;
865
866         for ( ;  ; i++)
867         {
868                 // count the cost
869                 pr_xfunction->builtinsprofile++;
870                 // wrap around
871                 if (i == svs.maxclients+1)
872                         i = 1;
873                 // look up the client's edict
874                 ent = EDICT_NUM(i);
875                 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
876                 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
877                         continue;
878                 // found a valid client (possibly the same one again)
879                 break;
880         }
881
882 // get the PVS for the entity
883         VectorAdd(ent->v->origin, ent->v->view_ofs, org);
884         checkpvsbytes = 0;
885         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
886                 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
887
888         return i;
889 }
890
891 /*
892 =================
893 PF_checkclient
894
895 Returns a client (or object that has a client enemy) that would be a
896 valid target.
897
898 If there is more than one valid option, they are cycled each frame
899
900 If (self.origin + self.viewofs) is not in the PVS of the current target,
901 it is not returned at all.
902
903 name checkclient ()
904 =================
905 */
906 int c_invis, c_notvis;
907 void PF_checkclient (void)
908 {
909         edict_t *ent, *self;
910         vec3_t  view;
911
912         // find a new check if on a new frame
913         if (sv.time - sv.lastchecktime >= 0.1)
914         {
915                 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
916                 sv.lastchecktime = sv.time;
917         }
918
919         // return check if it might be visible
920         ent = EDICT_NUM(sv.lastcheck);
921         if (ent->e->free || ent->v->health <= 0)
922         {
923                 RETURN_EDICT(sv.edicts);
924                 return;
925         }
926
927         // if current entity can't possibly see the check entity, return 0
928         self = PROG_TO_EDICT(pr_global_struct->self);
929         VectorAdd(self->v->origin, self->v->view_ofs, view);
930         if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
931         {
932                 c_notvis++;
933                 RETURN_EDICT(sv.edicts);
934                 return;
935         }
936
937         // might be able to see it
938         c_invis++;
939         RETURN_EDICT(ent);
940 }
941
942 //============================================================================
943
944
945 /*
946 =================
947 PF_stuffcmd
948
949 Sends text over to the client's execution buffer
950
951 stuffcmd (clientent, value)
952 =================
953 */
954 void PF_stuffcmd (void)
955 {
956         int             entnum;
957         char    *str;
958         client_t        *old;
959
960         entnum = G_EDICTNUM(OFS_PARM0);
961         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
962         {
963                 Con_Printf("Can't stuffcmd to a non-client");
964                 return;
965         }
966         str = G_STRING(OFS_PARM1);
967
968         old = host_client;
969         if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
970                 Host_ClientCommands ("%s", str);
971         host_client = old;
972 }
973
974 /*
975 =================
976 PF_localcmd
977
978 Sends text to server console
979
980 localcmd (string)
981 =================
982 */
983 void PF_localcmd (void)
984 {
985         Cbuf_AddText(G_STRING(OFS_PARM0));
986 }
987
988 /*
989 =================
990 PF_cvar
991
992 float cvar (string)
993 =================
994 */
995 void PF_cvar (void)
996 {
997         G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
998 }
999
1000 /*
1001 =================
1002 PF_cvar_set
1003
1004 float cvar (string)
1005 =================
1006 */
1007 void PF_cvar_set (void)
1008 {
1009         Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1010 }
1011
1012 /*
1013 =================
1014 PF_findradius
1015
1016 Returns a chain of entities that have origins within a spherical area
1017
1018 findradius (origin, radius)
1019 =================
1020 */
1021 void PF_findradius (void)
1022 {
1023         edict_t *ent, *chain;
1024         float radius;
1025         float radius2;
1026         float *org;
1027         float eorg[3];
1028         int i;
1029
1030         chain = (edict_t *)sv.edicts;
1031
1032         org = G_VECTOR(OFS_PARM0);
1033         radius = G_FLOAT(OFS_PARM1);
1034         radius2 = radius * radius;
1035
1036         ent = NEXT_EDICT(sv.edicts);
1037         for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1038         {
1039                 pr_xfunction->builtinsprofile++;
1040                 if (ent->e->free)
1041                         continue;
1042                 if (ent->v->solid == SOLID_NOT)
1043                         continue;
1044
1045                 // LordHavoc: compare against bounding box rather than center,
1046                 // and use DotProduct instead of Length, major speedup
1047                 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1048                 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1049                 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1050                 if (DotProduct(eorg, eorg) > radius2)
1051                         continue;
1052
1053                 ent->v->chain = EDICT_TO_PROG(chain);
1054                 chain = ent;
1055         }
1056
1057         RETURN_EDICT(chain);
1058 }
1059
1060
1061 /*
1062 =========
1063 PF_dprint
1064 =========
1065 */
1066 void PF_dprint (void)
1067 {
1068         char string[STRINGTEMP_LENGTH];
1069         if (developer.integer)
1070         {
1071                 PF_VarString(0, string, sizeof(string));
1072                 Con_Printf("%s",string);
1073         }
1074 }
1075
1076 void PF_ftos (void)
1077 {
1078         float v;
1079         char *s;
1080         v = G_FLOAT(OFS_PARM0);
1081
1082         s = PR_GetTempString();
1083         if ((float)((int)v) == v)
1084                 sprintf(s, "%i", (int)v);
1085         else
1086                 sprintf(s, "%f", v);
1087         G_INT(OFS_RETURN) = PR_SetString(s);
1088 }
1089
1090 void PF_fabs (void)
1091 {
1092         float   v;
1093         v = G_FLOAT(OFS_PARM0);
1094         G_FLOAT(OFS_RETURN) = fabs(v);
1095 }
1096
1097 void PF_vtos (void)
1098 {
1099         char *s;
1100         s = PR_GetTempString();
1101         sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1102         G_INT(OFS_RETURN) = PR_SetString(s);
1103 }
1104
1105 void PF_etos (void)
1106 {
1107         char *s;
1108         s = PR_GetTempString();
1109         sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1110         G_INT(OFS_RETURN) = PR_SetString(s);
1111 }
1112
1113 void PF_Spawn (void)
1114 {
1115         edict_t *ed;
1116         pr_xfunction->builtinsprofile += 20;
1117         ed = ED_Alloc();
1118         RETURN_EDICT(ed);
1119 }
1120
1121 void PF_Remove (void)
1122 {
1123         edict_t *ed;
1124         pr_xfunction->builtinsprofile += 20;
1125
1126         ed = G_EDICT(OFS_PARM0);
1127         if (ed == sv.edicts)
1128                 Host_Error("remove: tried to remove world\n");
1129         if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1130                 Host_Error("remove: tried to remove a client\n");
1131         // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1132         if (ed->e->free && developer.integer)
1133                 Con_Printf("remove: tried to remove an entity that was already removed\n");
1134         ED_Free (ed);
1135 }
1136
1137
1138 // entity (entity start, .string field, string match) find = #5;
1139 void PF_Find (void)
1140 {
1141         int             e;
1142         int             f;
1143         char    *s, *t;
1144         edict_t *ed;
1145
1146         e = G_EDICTNUM(OFS_PARM0);
1147         f = G_INT(OFS_PARM1);
1148         s = G_STRING(OFS_PARM2);
1149         if (!s || !s[0])
1150         {
1151                 RETURN_EDICT(sv.edicts);
1152                 return;
1153         }
1154
1155         for (e++ ; e < sv.num_edicts ; e++)
1156         {
1157                 pr_xfunction->builtinsprofile++;
1158                 ed = EDICT_NUM(e);
1159                 if (ed->e->free)
1160                         continue;
1161                 t = E_STRING(ed,f);
1162                 if (!t)
1163                         continue;
1164                 if (!strcmp(t,s))
1165                 {
1166                         RETURN_EDICT(ed);
1167                         return;
1168                 }
1169         }
1170
1171         RETURN_EDICT(sv.edicts);
1172 }
1173
1174 // LordHavoc: added this for searching float, int, and entity reference fields
1175 void PF_FindFloat (void)
1176 {
1177         int             e;
1178         int             f;
1179         float   s;
1180         edict_t *ed;
1181
1182         e = G_EDICTNUM(OFS_PARM0);
1183         f = G_INT(OFS_PARM1);
1184         s = G_FLOAT(OFS_PARM2);
1185
1186         for (e++ ; e < sv.num_edicts ; e++)
1187         {
1188                 pr_xfunction->builtinsprofile++;
1189                 ed = EDICT_NUM(e);
1190                 if (ed->e->free)
1191                         continue;
1192                 if (E_FLOAT(ed,f) == s)
1193                 {
1194                         RETURN_EDICT(ed);
1195                         return;
1196                 }
1197         }
1198
1199         RETURN_EDICT(sv.edicts);
1200 }
1201
1202 // chained search for strings in entity fields
1203 // entity(.string field, string match) findchain = #402;
1204 void PF_findchain (void)
1205 {
1206         int             i;
1207         int             f;
1208         char    *s, *t;
1209         edict_t *ent, *chain;
1210
1211         chain = (edict_t *)sv.edicts;
1212
1213         f = G_INT(OFS_PARM0);
1214         s = G_STRING(OFS_PARM1);
1215         if (!s || !s[0])
1216         {
1217                 RETURN_EDICT(sv.edicts);
1218                 return;
1219         }
1220
1221         ent = NEXT_EDICT(sv.edicts);
1222         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1223         {
1224                 pr_xfunction->builtinsprofile++;
1225                 if (ent->e->free)
1226                         continue;
1227                 t = E_STRING(ent,f);
1228                 if (!t)
1229                         continue;
1230                 if (strcmp(t,s))
1231                         continue;
1232
1233                 ent->v->chain = EDICT_TO_PROG(chain);
1234                 chain = ent;
1235         }
1236
1237         RETURN_EDICT(chain);
1238 }
1239
1240 // LordHavoc: chained search for float, int, and entity reference fields
1241 // entity(.string field, float match) findchainfloat = #403;
1242 void PF_findchainfloat (void)
1243 {
1244         int             i;
1245         int             f;
1246         float   s;
1247         edict_t *ent, *chain;
1248
1249         chain = (edict_t *)sv.edicts;
1250
1251         f = G_INT(OFS_PARM0);
1252         s = G_FLOAT(OFS_PARM1);
1253
1254         ent = NEXT_EDICT(sv.edicts);
1255         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1256         {
1257                 pr_xfunction->builtinsprofile++;
1258                 if (ent->e->free)
1259                         continue;
1260                 if (E_FLOAT(ent,f) != s)
1261                         continue;
1262
1263                 ent->v->chain = EDICT_TO_PROG(chain);
1264                 chain = ent;
1265         }
1266
1267         RETURN_EDICT(chain);
1268 }
1269
1270 void PR_CheckEmptyString (char *s)
1271 {
1272         if (s[0] <= ' ')
1273                 Host_Error ("Bad string");
1274 }
1275
1276 void PF_precache_file (void)
1277 {       // precache_file is only used to copy files with qcc, it does nothing
1278         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1279 }
1280
1281 void PF_precache_sound (void)
1282 {
1283         char    *s;
1284         int             i;
1285
1286         if (sv.state != ss_loading)
1287                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1288
1289         s = G_STRING(OFS_PARM0);
1290         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1291         PR_CheckEmptyString (s);
1292
1293         for (i=0 ; i<MAX_SOUNDS ; i++)
1294         {
1295                 if (!sv.sound_precache[i])
1296                 {
1297                         sv.sound_precache[i] = s;
1298                         return;
1299                 }
1300                 if (!strcmp(sv.sound_precache[i], s))
1301                         return;
1302         }
1303         Host_Error ("PF_precache_sound: overflow");
1304 }
1305
1306 void PF_precache_model (void)
1307 {
1308         char    *s;
1309         int             i;
1310
1311         if (sv.state != ss_loading)
1312                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1313
1314         s = G_STRING(OFS_PARM0);
1315         if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1316                 return;
1317         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1318         PR_CheckEmptyString (s);
1319
1320         for (i=0 ; i<MAX_MODELS ; i++)
1321         {
1322                 if (!sv.model_precache[i])
1323                 {
1324                         sv.model_precache[i] = s;
1325                         sv.models[i] = Mod_ForName (s, true, false, false);
1326                         return;
1327                 }
1328                 if (!strcmp(sv.model_precache[i], s))
1329                         return;
1330         }
1331         Host_Error ("PF_precache_model: overflow");
1332 }
1333
1334
1335 void PF_coredump (void)
1336 {
1337         ED_PrintEdicts ();
1338 }
1339
1340 void PF_traceon (void)
1341 {
1342         pr_trace = true;
1343 }
1344
1345 void PF_traceoff (void)
1346 {
1347         pr_trace = false;
1348 }
1349
1350 void PF_eprint (void)
1351 {
1352         ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1353 }
1354
1355 /*
1356 ===============
1357 PF_walkmove
1358
1359 float(float yaw, float dist) walkmove
1360 ===============
1361 */
1362 void PF_walkmove (void)
1363 {
1364         edict_t *ent;
1365         float   yaw, dist;
1366         vec3_t  move;
1367         mfunction_t     *oldf;
1368         int     oldself;
1369
1370         ent = PROG_TO_EDICT(pr_global_struct->self);
1371         if (ent == sv.edicts)
1372                 Host_Error("walkmove: can not modify world entity\n");
1373         if (ent->e->free)
1374                 Host_Error("walkmove: can not modify free entity\n");
1375         yaw = G_FLOAT(OFS_PARM0);
1376         dist = G_FLOAT(OFS_PARM1);
1377
1378         if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1379         {
1380                 G_FLOAT(OFS_RETURN) = 0;
1381                 return;
1382         }
1383
1384         yaw = yaw*M_PI*2 / 360;
1385
1386         move[0] = cos(yaw)*dist;
1387         move[1] = sin(yaw)*dist;
1388         move[2] = 0;
1389
1390 // save program state, because SV_movestep may call other progs
1391         oldf = pr_xfunction;
1392         oldself = pr_global_struct->self;
1393
1394         G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1395
1396
1397 // restore program state
1398         pr_xfunction = oldf;
1399         pr_global_struct->self = oldself;
1400 }
1401
1402 /*
1403 ===============
1404 PF_droptofloor
1405
1406 void() droptofloor
1407 ===============
1408 */
1409 void PF_droptofloor (void)
1410 {
1411         edict_t         *ent;
1412         vec3_t          end;
1413         trace_t         trace;
1414
1415         ent = PROG_TO_EDICT(pr_global_struct->self);
1416         if (ent == sv.edicts)
1417                 Host_Error("droptofloor: can not modify world entity\n");
1418         if (ent->e->free)
1419                 Host_Error("droptofloor: can not modify free entity\n");
1420
1421         VectorCopy (ent->v->origin, end);
1422         end[2] -= 256;
1423
1424         trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1425
1426         if (trace.fraction == 1)
1427                 G_FLOAT(OFS_RETURN) = 0;
1428         else
1429         {
1430                 VectorCopy (trace.endpos, ent->v->origin);
1431                 SV_LinkEdict (ent, false);
1432                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1433                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1434                 G_FLOAT(OFS_RETURN) = 1;
1435                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1436                 ent->e->suspendedinairflag = true;
1437         }
1438 }
1439
1440 /*
1441 ===============
1442 PF_lightstyle
1443
1444 void(float style, string value) lightstyle
1445 ===============
1446 */
1447 void PF_lightstyle (void)
1448 {
1449         int             style;
1450         char    *val;
1451         client_t        *client;
1452         int                     j;
1453
1454         style = G_FLOAT(OFS_PARM0);
1455         val = G_STRING(OFS_PARM1);
1456
1457 // change the string in sv
1458         sv.lightstyles[style] = val;
1459
1460 // send message to all clients on this server
1461         if (sv.state != ss_active)
1462                 return;
1463
1464         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1465         {
1466                 if (client->netconnection)
1467                 {
1468                         MSG_WriteChar (&client->message, svc_lightstyle);
1469                         MSG_WriteChar (&client->message,style);
1470                         MSG_WriteString (&client->message, val);
1471                 }
1472         }
1473 }
1474
1475 void PF_rint (void)
1476 {
1477         float   f;
1478         f = G_FLOAT(OFS_PARM0);
1479         if (f > 0)
1480                 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1481         else
1482                 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1483 }
1484 void PF_floor (void)
1485 {
1486         G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1487 }
1488 void PF_ceil (void)
1489 {
1490         G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1491 }
1492
1493
1494 /*
1495 =============
1496 PF_checkbottom
1497 =============
1498 */
1499 void PF_checkbottom (void)
1500 {
1501         G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1502 }
1503
1504 /*
1505 =============
1506 PF_pointcontents
1507 =============
1508 */
1509 void PF_pointcontents (void)
1510 {
1511         G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1512 }
1513
1514 /*
1515 =============
1516 PF_nextent
1517
1518 entity nextent(entity)
1519 =============
1520 */
1521 void PF_nextent (void)
1522 {
1523         int             i;
1524         edict_t *ent;
1525
1526         i = G_EDICTNUM(OFS_PARM0);
1527         while (1)
1528         {
1529                 pr_xfunction->builtinsprofile++;
1530                 i++;
1531                 if (i == sv.num_edicts)
1532                 {
1533                         RETURN_EDICT(sv.edicts);
1534                         return;
1535                 }
1536                 ent = EDICT_NUM(i);
1537                 if (!ent->e->free)
1538                 {
1539                         RETURN_EDICT(ent);
1540                         return;
1541                 }
1542         }
1543 }
1544
1545 /*
1546 =============
1547 PF_aim
1548
1549 Pick a vector for the player to shoot along
1550 vector aim(entity, missilespeed)
1551 =============
1552 */
1553 void PF_aim (void)
1554 {
1555         edict_t *ent, *check, *bestent;
1556         vec3_t  start, dir, end, bestdir;
1557         int             i, j;
1558         trace_t tr;
1559         float   dist, bestdist;
1560         float   speed;
1561
1562         ent = G_EDICT(OFS_PARM0);
1563         if (ent == sv.edicts)
1564                 Host_Error("aim: can not use world entity\n");
1565         if (ent->e->free)
1566                 Host_Error("aim: can not use free entity\n");
1567         speed = G_FLOAT(OFS_PARM1);
1568
1569         VectorCopy (ent->v->origin, start);
1570         start[2] += 20;
1571
1572 // try sending a trace straight
1573         VectorCopy (pr_global_struct->v_forward, dir);
1574         VectorMA (start, 2048, dir, end);
1575         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1576         if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1577         && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1578         {
1579                 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1580                 return;
1581         }
1582
1583
1584 // try all possible entities
1585         VectorCopy (dir, bestdir);
1586         bestdist = sv_aim.value;
1587         bestent = NULL;
1588
1589         check = NEXT_EDICT(sv.edicts);
1590         for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1591         {
1592                 pr_xfunction->builtinsprofile++;
1593                 if (check->v->takedamage != DAMAGE_AIM)
1594                         continue;
1595                 if (check == ent)
1596                         continue;
1597                 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1598                         continue;       // don't aim at teammate
1599                 for (j=0 ; j<3 ; j++)
1600                         end[j] = check->v->origin[j]
1601                         + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1602                 VectorSubtract (end, start, dir);
1603                 VectorNormalize (dir);
1604                 dist = DotProduct (dir, pr_global_struct->v_forward);
1605                 if (dist < bestdist)
1606                         continue;       // to far to turn
1607                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1608                 if (tr.ent == check)
1609                 {       // can shoot at this one
1610                         bestdist = dist;
1611                         bestent = check;
1612                 }
1613         }
1614
1615         if (bestent)
1616         {
1617                 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1618                 dist = DotProduct (dir, pr_global_struct->v_forward);
1619                 VectorScale (pr_global_struct->v_forward, dist, end);
1620                 end[2] = dir[2];
1621                 VectorNormalize (end);
1622                 VectorCopy (end, G_VECTOR(OFS_RETURN));
1623         }
1624         else
1625         {
1626                 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1627         }
1628 }
1629
1630 /*
1631 ==============
1632 PF_changeyaw
1633
1634 This was a major timewaster in progs, so it was converted to C
1635 ==============
1636 */
1637 void PF_changeyaw (void)
1638 {
1639         edict_t         *ent;
1640         float           ideal, current, move, speed;
1641
1642         ent = PROG_TO_EDICT(pr_global_struct->self);
1643         if (ent == sv.edicts)
1644                 Host_Error("changeyaw: can not modify world entity\n");
1645         if (ent->e->free)
1646                 Host_Error("changeyaw: can not modify free entity\n");
1647         current = ANGLEMOD(ent->v->angles[1]);
1648         ideal = ent->v->ideal_yaw;
1649         speed = ent->v->yaw_speed;
1650
1651         if (current == ideal)
1652                 return;
1653         move = ideal - current;
1654         if (ideal > current)
1655         {
1656                 if (move >= 180)
1657                         move = move - 360;
1658         }
1659         else
1660         {
1661                 if (move <= -180)
1662                         move = move + 360;
1663         }
1664         if (move > 0)
1665         {
1666                 if (move > speed)
1667                         move = speed;
1668         }
1669         else
1670         {
1671                 if (move < -speed)
1672                         move = -speed;
1673         }
1674
1675         ent->v->angles[1] = ANGLEMOD (current + move);
1676 }
1677
1678 /*
1679 ==============
1680 PF_changepitch
1681 ==============
1682 */
1683 void PF_changepitch (void)
1684 {
1685         edict_t         *ent;
1686         float           ideal, current, move, speed;
1687         eval_t          *val;
1688
1689         ent = G_EDICT(OFS_PARM0);
1690         if (ent == sv.edicts)
1691                 Host_Error("changepitch: can not modify world entity\n");
1692         if (ent->e->free)
1693                 Host_Error("changepitch: can not modify free entity\n");
1694         current = ANGLEMOD( ent->v->angles[0] );
1695         if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1696                 ideal = val->_float;
1697         else
1698         {
1699                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1700                 return;
1701         }
1702         if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1703                 speed = val->_float;
1704         else
1705         {
1706                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1707                 return;
1708         }
1709
1710         if (current == ideal)
1711                 return;
1712         move = ideal - current;
1713         if (ideal > current)
1714         {
1715                 if (move >= 180)
1716                         move = move - 360;
1717         }
1718         else
1719         {
1720                 if (move <= -180)
1721                         move = move + 360;
1722         }
1723         if (move > 0)
1724         {
1725                 if (move > speed)
1726                         move = speed;
1727         }
1728         else
1729         {
1730                 if (move < -speed)
1731                         move = -speed;
1732         }
1733
1734         ent->v->angles[0] = ANGLEMOD (current + move);
1735 }
1736
1737 /*
1738 ===============================================================================
1739
1740 MESSAGE WRITING
1741
1742 ===============================================================================
1743 */
1744
1745 #define MSG_BROADCAST   0               // unreliable to all
1746 #define MSG_ONE                 1               // reliable to one (msg_entity)
1747 #define MSG_ALL                 2               // reliable to all
1748 #define MSG_INIT                3               // write to the init string
1749
1750 sizebuf_t *WriteDest (void)
1751 {
1752         int             entnum;
1753         int             dest;
1754         edict_t *ent;
1755
1756         dest = G_FLOAT(OFS_PARM0);
1757         switch (dest)
1758         {
1759         case MSG_BROADCAST:
1760                 return &sv.datagram;
1761
1762         case MSG_ONE:
1763                 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1764                 entnum = NUM_FOR_EDICT(ent);
1765                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1766                         Host_Error("WriteDest: tried to write to non-client\n");
1767                 return &svs.clients[entnum-1].message;
1768
1769         case MSG_ALL:
1770                 return &sv.reliable_datagram;
1771
1772         case MSG_INIT:
1773                 return &sv.signon;
1774
1775         default:
1776                 Host_Error ("WriteDest: bad destination");
1777                 break;
1778         }
1779
1780         return NULL;
1781 }
1782
1783 void PF_WriteByte (void)
1784 {
1785         MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1786 }
1787
1788 void PF_WriteChar (void)
1789 {
1790         MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1791 }
1792
1793 void PF_WriteShort (void)
1794 {
1795         MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1796 }
1797
1798 void PF_WriteLong (void)
1799 {
1800         MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1801 }
1802
1803 void PF_WriteAngle (void)
1804 {
1805         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1806 }
1807
1808 void PF_WriteCoord (void)
1809 {
1810         MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1811 }
1812
1813 void PF_WriteString (void)
1814 {
1815         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1816 }
1817
1818
1819 void PF_WriteEntity (void)
1820 {
1821         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1822 }
1823
1824 //=============================================================================
1825
1826 void PF_makestatic (void)
1827 {
1828         edict_t *ent;
1829         int i, large;
1830
1831         ent = G_EDICT(OFS_PARM0);
1832         if (ent == sv.edicts)
1833                 Host_Error("makestatic: can not modify world entity\n");
1834         if (ent->e->free)
1835                 Host_Error("makestatic: can not modify free entity\n");
1836
1837         large = false;
1838         if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1839                 large = true;
1840
1841         if (large)
1842         {
1843                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1844                 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1845                 MSG_WriteShort (&sv.signon, ent->v->frame);
1846         }
1847         else
1848         {
1849                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1850                 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1851                 MSG_WriteByte (&sv.signon, ent->v->frame);
1852         }
1853
1854         MSG_WriteByte (&sv.signon, ent->v->colormap);
1855         MSG_WriteByte (&sv.signon, ent->v->skin);
1856         for (i=0 ; i<3 ; i++)
1857         {
1858                 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1859                 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1860         }
1861
1862 // throw the entity away now
1863         ED_Free (ent);
1864 }
1865
1866 //=============================================================================
1867
1868 /*
1869 ==============
1870 PF_setspawnparms
1871 ==============
1872 */
1873 void PF_setspawnparms (void)
1874 {
1875         edict_t *ent;
1876         int             i;
1877         client_t        *client;
1878
1879         ent = G_EDICT(OFS_PARM0);
1880         i = NUM_FOR_EDICT(ent);
1881         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1882         {
1883                 Con_Printf("tried to setspawnparms on a non-client\n");
1884                 return;
1885         }
1886
1887         // copy spawn parms out of the client_t
1888         client = svs.clients + i-1;
1889         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1890                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1891 }
1892
1893 /*
1894 ==============
1895 PF_changelevel
1896 ==============
1897 */
1898 void PF_changelevel (void)
1899 {
1900         char    *s;
1901
1902 // make sure we don't issue two changelevels
1903         if (svs.changelevel_issued)
1904                 return;
1905         svs.changelevel_issued = true;
1906
1907         s = G_STRING(OFS_PARM0);
1908         Cbuf_AddText (va("changelevel %s\n",s));
1909 }
1910
1911 void PF_sin (void)
1912 {
1913         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1914 }
1915
1916 void PF_cos (void)
1917 {
1918         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1919 }
1920
1921 void PF_sqrt (void)
1922 {
1923         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1924 }
1925
1926 /*
1927 =================
1928 PF_RandomVec
1929
1930 Returns a vector of length < 1
1931
1932 randomvec()
1933 =================
1934 */
1935 void PF_randomvec (void)
1936 {
1937         vec3_t          temp;
1938         do
1939         {
1940                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1941                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1942                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1943         }
1944         while (DotProduct(temp, temp) >= 1);
1945         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1946 }
1947
1948 /*
1949 =================
1950 PF_GetLight
1951
1952 Returns a color vector indicating the lighting at the requested point.
1953
1954 (Internal Operation note: actually measures the light beneath the point, just like
1955                           the model lighting on the client)
1956
1957 getlight(vector)
1958 =================
1959 */
1960 void PF_GetLight (void)
1961 {
1962         vec3_t ambientcolor, diffusecolor, diffusenormal;
1963         vec_t *p;
1964         p = G_VECTOR(OFS_PARM0);
1965         VectorClear(ambientcolor);
1966         VectorClear(diffusecolor);
1967         VectorClear(diffusenormal);
1968         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1969                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1970         VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1971 }
1972
1973 #define MAX_QC_CVARS 128
1974 cvar_t qc_cvar[MAX_QC_CVARS];
1975 int currentqc_cvar;
1976
1977 void PF_registercvar (void)
1978 {
1979         char *name, *value;
1980         cvar_t *variable;
1981         name = G_STRING(OFS_PARM0);
1982         value = G_STRING(OFS_PARM1);
1983         G_FLOAT(OFS_RETURN) = 0;
1984 // first check to see if it has already been defined
1985         if (Cvar_FindVar (name))
1986                 return;
1987
1988 // check for overlap with a command
1989         if (Cmd_Exists (name))
1990         {
1991                 Con_Printf ("PF_registercvar: %s is a command\n", name);
1992                 return;
1993         }
1994
1995         if (currentqc_cvar >= MAX_QC_CVARS)
1996                 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1997
1998 // copy the name and value
1999         variable = &qc_cvar[currentqc_cvar++];
2000         variable->name = Z_Malloc (strlen(name)+1);
2001         strcpy (variable->name, name);
2002         variable->string = Z_Malloc (strlen(value)+1);
2003         strcpy (variable->string, value);
2004         variable->value = atof (value);
2005
2006         Cvar_RegisterVariable(variable);
2007         G_FLOAT(OFS_RETURN) = 1; // success
2008 }
2009
2010 /*
2011 =================
2012 PF_min
2013
2014 returns the minimum of two supplied floats
2015
2016 min(a, b)
2017 =================
2018 */
2019 void PF_min (void)
2020 {
2021         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2022         if (pr_argc == 2)
2023                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2024         else if (pr_argc >= 3)
2025         {
2026                 int i;
2027                 float f = G_FLOAT(OFS_PARM0);
2028                 for (i = 1;i < pr_argc;i++)
2029                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
2030                                 f = G_FLOAT((OFS_PARM0+i*3));
2031                 G_FLOAT(OFS_RETURN) = f;
2032         }
2033         else
2034                 Host_Error("min: must supply at least 2 floats\n");
2035 }
2036
2037 /*
2038 =================
2039 PF_max
2040
2041 returns the maximum of two supplied floats
2042
2043 max(a, b)
2044 =================
2045 */
2046 void PF_max (void)
2047 {
2048         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2049         if (pr_argc == 2)
2050                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2051         else if (pr_argc >= 3)
2052         {
2053                 int i;
2054                 float f = G_FLOAT(OFS_PARM0);
2055                 for (i = 1;i < pr_argc;i++)
2056                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
2057                                 f = G_FLOAT((OFS_PARM0+i*3));
2058                 G_FLOAT(OFS_RETURN) = f;
2059         }
2060         else
2061                 Host_Error("max: must supply at least 2 floats\n");
2062 }
2063
2064 /*
2065 =================
2066 PF_bound
2067
2068 returns number bounded by supplied range
2069
2070 min(min, value, max)
2071 =================
2072 */
2073 void PF_bound (void)
2074 {
2075         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2076 }
2077
2078 /*
2079 =================
2080 PF_pow
2081
2082 returns a raised to power b
2083
2084 pow(a, b)
2085 =================
2086 */
2087 void PF_pow (void)
2088 {
2089         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2090 }
2091
2092 /*
2093 =================
2094 PF_copyentity
2095
2096 copies data from one entity to another
2097
2098 copyentity(src, dst)
2099 =================
2100 */
2101 void PF_copyentity (void)
2102 {
2103         edict_t *in, *out;
2104         in = G_EDICT(OFS_PARM0);
2105         if (in == sv.edicts)
2106                 Host_Error("copyentity: can not read world entity\n");
2107         if (in->e->free)
2108                 Host_Error("copyentity: can not read free entity\n");
2109         out = G_EDICT(OFS_PARM1);
2110         if (out == sv.edicts)
2111                 Host_Error("copyentity: can not modify world entity\n");
2112         if (out->e->free)
2113                 Host_Error("copyentity: can not modify free entity\n");
2114         memcpy(out->v, in->v, progs->entityfields * 4);
2115 }
2116
2117 /*
2118 =================
2119 PF_setcolor
2120
2121 sets the color of a client and broadcasts the update to all connected clients
2122
2123 setcolor(clientent, value)
2124 =================
2125 */
2126 void PF_setcolor (void)
2127 {
2128         client_t *client;
2129         int entnum, i;
2130         eval_t *val;
2131
2132         entnum = G_EDICTNUM(OFS_PARM0);
2133         i = G_FLOAT(OFS_PARM1);
2134
2135         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2136         {
2137                 Con_Printf ("tried to setcolor a non-client\n");
2138                 return;
2139         }
2140
2141         client = svs.clients + entnum-1;
2142         if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2143                 val->_float = i;
2144         client->colors = i;
2145         client->old_colors = i;
2146         client->edict->v->team = (i & 15) + 1;
2147
2148         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2149         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2150         MSG_WriteByte (&sv.reliable_datagram, i);
2151 }
2152
2153 /*
2154 =================
2155 PF_effect
2156
2157 effect(origin, modelname, startframe, framecount, framerate)
2158 =================
2159 */
2160 void PF_effect (void)
2161 {
2162         char *s;
2163         s = G_STRING(OFS_PARM1);
2164         if (!s || !s[0])
2165                 Host_Error("effect: no model specified\n");
2166
2167         SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2168 }
2169
2170 void PF_te_blood (void)
2171 {
2172         if (G_FLOAT(OFS_PARM2) < 1)
2173                 return;
2174         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2175         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2176         // origin
2177         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2178         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2179         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2180         // velocity
2181         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2182         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2183         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2184         // count
2185         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2186 }
2187
2188 void PF_te_bloodshower (void)
2189 {
2190         if (G_FLOAT(OFS_PARM3) < 1)
2191                 return;
2192         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2193         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2194         // min
2195         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2196         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2197         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2198         // max
2199         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2200         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2201         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2202         // speed
2203         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2204         // count
2205         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2206 }
2207
2208 void PF_te_explosionrgb (void)
2209 {
2210         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2211         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2212         // origin
2213         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2214         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2215         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2216         // color
2217         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2218         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2219         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2220 }
2221
2222 void PF_te_particlecube (void)
2223 {
2224         if (G_FLOAT(OFS_PARM3) < 1)
2225                 return;
2226         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2227         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2228         // min
2229         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2230         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2231         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2232         // max
2233         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2234         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2235         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2236         // velocity
2237         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2238         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2239         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2240         // count
2241         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2242         // color
2243         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2244         // gravity true/false
2245         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2246         // randomvel
2247         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2248 }
2249
2250 void PF_te_particlerain (void)
2251 {
2252         if (G_FLOAT(OFS_PARM3) < 1)
2253                 return;
2254         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2255         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2256         // min
2257         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2258         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2259         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2260         // max
2261         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2262         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2263         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2264         // velocity
2265         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2266         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2267         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2268         // count
2269         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2270         // color
2271         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2272 }
2273
2274 void PF_te_particlesnow (void)
2275 {
2276         if (G_FLOAT(OFS_PARM3) < 1)
2277                 return;
2278         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2279         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2280         // min
2281         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2282         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2283         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2284         // max
2285         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2286         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2287         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2288         // velocity
2289         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2290         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2291         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2292         // count
2293         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2294         // color
2295         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2296 }
2297
2298 void PF_te_spark (void)
2299 {
2300         if (G_FLOAT(OFS_PARM2) < 1)
2301                 return;
2302         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2303         MSG_WriteByte(&sv.datagram, TE_SPARK);
2304         // origin
2305         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2306         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2307         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2308         // velocity
2309         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2310         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2311         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2312         // count
2313         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2314 }
2315
2316 void PF_te_gunshotquad (void)
2317 {
2318         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2319         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2320         // origin
2321         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2322         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2323         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2324 }
2325
2326 void PF_te_spikequad (void)
2327 {
2328         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2329         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2330         // origin
2331         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2332         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2333         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2334 }
2335
2336 void PF_te_superspikequad (void)
2337 {
2338         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2339         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2340         // origin
2341         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2342         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2343         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2344 }
2345
2346 void PF_te_explosionquad (void)
2347 {
2348         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2349         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2350         // origin
2351         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2352         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2353         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2354 }
2355
2356 void PF_te_smallflash (void)
2357 {
2358         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2359         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2360         // origin
2361         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2362         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2363         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2364 }
2365
2366 void PF_te_customflash (void)
2367 {
2368         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2369                 return;
2370         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2371         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2372         // origin
2373         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2374         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2375         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2376         // radius
2377         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2378         // lifetime
2379         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2380         // color
2381         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2382         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2383         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2384 }
2385
2386 void PF_te_gunshot (void)
2387 {
2388         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2389         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2390         // origin
2391         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2392         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2393         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2394 }
2395
2396 void PF_te_spike (void)
2397 {
2398         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2399         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2400         // origin
2401         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2402         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2403         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2404 }
2405
2406 void PF_te_superspike (void)
2407 {
2408         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2409         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2410         // origin
2411         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2412         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2413         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2414 }
2415
2416 void PF_te_explosion (void)
2417 {
2418         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2419         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2420         // origin
2421         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2422         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2423         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2424 }
2425
2426 void PF_te_tarexplosion (void)
2427 {
2428         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2429         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2430         // origin
2431         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2432         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2433         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2434 }
2435
2436 void PF_te_wizspike (void)
2437 {
2438         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2439         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2440         // origin
2441         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2442         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2443         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2444 }
2445
2446 void PF_te_knightspike (void)
2447 {
2448         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2449         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2450         // origin
2451         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2452         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2453         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2454 }
2455
2456 void PF_te_lavasplash (void)
2457 {
2458         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2459         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2460         // origin
2461         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2462         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2463         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2464 }
2465
2466 void PF_te_teleport (void)
2467 {
2468         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2469         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2470         // origin
2471         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2472         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2473         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2474 }
2475
2476 void PF_te_explosion2 (void)
2477 {
2478         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2479         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2480         // origin
2481         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2482         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2483         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2484         // color
2485         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2486 }
2487
2488 void PF_te_lightning1 (void)
2489 {
2490         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2491         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2492         // owner entity
2493         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2494         // start
2495         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2496         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2497         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2498         // end
2499         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2500         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2501         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2502 }
2503
2504 void PF_te_lightning2 (void)
2505 {
2506         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2507         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2508         // owner entity
2509         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2510         // start
2511         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2512         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2513         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2514         // end
2515         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2516         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2517         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2518 }
2519
2520 void PF_te_lightning3 (void)
2521 {
2522         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2523         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2524         // owner entity
2525         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2526         // start
2527         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2528         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2529         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2530         // end
2531         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2532         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2533         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2534 }
2535
2536 void PF_te_beam (void)
2537 {
2538         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2539         MSG_WriteByte(&sv.datagram, TE_BEAM);
2540         // owner entity
2541         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2542         // start
2543         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2544         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2545         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2546         // end
2547         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2548         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2549         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2550 }
2551
2552 void PF_te_plasmaburn (void)
2553 {
2554         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2555         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2556         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2557         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2558         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2559 }
2560
2561 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2562 {
2563         int i, j;
2564         vec3_t v1, clipplanenormal, normal;
2565         vec_t clipplanedist, clipdist;
2566         VectorCopy(p, out);
2567         if (surf->flags & SURF_PLANEBACK)
2568                 VectorNegate(surf->plane->normal, normal);
2569         else
2570                 VectorCopy(surf->plane->normal, normal);
2571         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2572         {
2573                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2574                 VectorNormalizeFast(v1);
2575                 CrossProduct(v1, normal, clipplanenormal);
2576                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2577                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2578                 if (clipdist > 0)
2579                 {
2580                         clipdist = -clipdist;
2581                         VectorMA(out, clipdist, clipplanenormal, out);
2582                 }
2583         }
2584 }
2585
2586 static msurface_t *getsurface(edict_t *ed, int surfnum)
2587 {
2588         int modelindex;
2589         model_t *model;
2590         if (!ed || ed->e->free)
2591                 return NULL;
2592         modelindex = ed->v->modelindex;
2593         if (modelindex < 1 || modelindex >= MAX_MODELS)
2594                 return NULL;
2595         model = sv.models[modelindex];
2596         if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2597                 return NULL;
2598         return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2599 }
2600
2601
2602 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2603 void PF_getsurfacenumpoints(void)
2604 {
2605         msurface_t *surf;
2606         // return 0 if no such surface
2607         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2608         {
2609                 G_FLOAT(OFS_RETURN) = 0;
2610                 return;
2611         }
2612
2613         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2614 }
2615 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2616 void PF_getsurfacepoint(void)
2617 {
2618         edict_t *ed;
2619         msurface_t *surf;
2620         int pointnum;
2621         VectorClear(G_VECTOR(OFS_RETURN));
2622         ed = G_EDICT(OFS_PARM0);
2623         if (!ed || ed->e->free)
2624                 return;
2625         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2626                 return;
2627         pointnum = G_FLOAT(OFS_PARM2);
2628         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2629                 return;
2630         // FIXME: implement rotation/scaling
2631         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2632 }
2633 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2634 void PF_getsurfacenormal(void)
2635 {
2636         msurface_t *surf;
2637         VectorClear(G_VECTOR(OFS_RETURN));
2638         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2639                 return;
2640         // FIXME: implement rotation/scaling
2641         if (surf->flags & SURF_PLANEBACK)
2642                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2643         else
2644                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2645 }
2646 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2647 void PF_getsurfacetexture(void)
2648 {
2649         msurface_t *surf;
2650         G_INT(OFS_RETURN) = 0;
2651         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2652                 return;
2653         G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2654 }
2655 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2656 void PF_getsurfacenearpoint(void)
2657 {
2658         int surfnum, best, modelindex;
2659         vec3_t clipped, p;
2660         vec_t dist, bestdist;
2661         edict_t *ed;
2662         model_t *model;
2663         msurface_t *surf;
2664         vec_t *point;
2665         G_FLOAT(OFS_RETURN) = -1;
2666         ed = G_EDICT(OFS_PARM0);
2667         point = G_VECTOR(OFS_PARM1);
2668
2669         if (!ed || ed->e->free)
2670                 return;
2671         modelindex = ed->v->modelindex;
2672         if (modelindex < 1 || modelindex >= MAX_MODELS)
2673                 return;
2674         model = sv.models[modelindex];
2675         if (!model->brushq1.numsurfaces)
2676                 return;
2677
2678         // FIXME: implement rotation/scaling
2679         VectorSubtract(point, ed->v->origin, p);
2680         best = -1;
2681         bestdist = 1000000000;
2682         for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2683         {
2684                 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2685                 dist = PlaneDiff(p, surf->plane);
2686                 dist = dist * dist;
2687                 if (dist < bestdist)
2688                 {
2689                         clippointtosurface(surf, p, clipped);
2690                         VectorSubtract(clipped, p, clipped);
2691                         dist += DotProduct(clipped, clipped);
2692                         if (dist < bestdist)
2693                         {
2694                                 best = surfnum;
2695                                 bestdist = dist;
2696                         }
2697                 }
2698         }
2699         G_FLOAT(OFS_RETURN) = best;
2700 }
2701 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2702 void PF_getsurfaceclippedpoint(void)
2703 {
2704         edict_t *ed;
2705         msurface_t *surf;
2706         vec3_t p, out;
2707         VectorClear(G_VECTOR(OFS_RETURN));
2708         ed = G_EDICT(OFS_PARM0);
2709         if (!ed || ed->e->free)
2710                 return;
2711         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2712                 return;
2713         // FIXME: implement rotation/scaling
2714         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2715         clippointtosurface(surf, p, out);
2716         // FIXME: implement rotation/scaling
2717         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2718 }
2719
2720 #define MAX_PRFILES 256
2721
2722 qfile_t *pr_files[MAX_PRFILES];
2723
2724 void PR_Files_Init(void)
2725 {
2726         memset(pr_files, 0, sizeof(pr_files));
2727 }
2728
2729 void PR_Files_CloseAll(void)
2730 {
2731         int i;
2732         for (i = 0;i < MAX_PRFILES;i++)
2733         {
2734                 if (pr_files[i])
2735                         FS_Close(pr_files[i]);
2736                 pr_files[i] = NULL;
2737         }
2738 }
2739
2740 //float(string s) stof = #81; // get numerical value from a string
2741 void PF_stof(void)
2742 {
2743         char string[STRINGTEMP_LENGTH];
2744         PF_VarString(0, string, sizeof(string));
2745         G_FLOAT(OFS_RETURN) = atof(string);
2746 }
2747
2748 //float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
2749 void PF_fopen(void)
2750 {
2751         int filenum, mode;
2752         char *modestring, *filename;
2753         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2754                 if (pr_files[filenum] == NULL)
2755                         break;
2756         if (filenum >= MAX_PRFILES)
2757         {
2758                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2759                 G_FLOAT(OFS_RETURN) = -2;
2760                 return;
2761         }
2762         mode = G_FLOAT(OFS_PARM1);
2763         switch(mode)
2764         {
2765         case 0: // FILE_READ
2766                 modestring = "rb";
2767                 break;
2768         case 1: // FILE_APPEND
2769                 modestring = "ab";
2770                 break;
2771         case 2: // FILE_WRITE
2772                 modestring = "wb";
2773                 break;
2774         default:
2775                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2776                 G_FLOAT(OFS_RETURN) = -3;
2777                 return;
2778         }
2779         filename = G_STRING(OFS_PARM0);
2780         // .. is parent directory on many platforms
2781         // / is parent directory on Amiga
2782         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2783         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2784         if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2785         {
2786                 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2787                 G_FLOAT(OFS_RETURN) = -4;
2788                 return;
2789         }
2790         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2791         if (pr_files[filenum] == NULL)
2792                 G_FLOAT(OFS_RETURN) = -1;
2793         else
2794                 G_FLOAT(OFS_RETURN) = filenum;
2795 }
2796
2797 //void(float fhandle) fclose = #111; // closes a file
2798 void PF_fclose(void)
2799 {
2800         int filenum = G_FLOAT(OFS_PARM0);
2801         if (filenum < 0 || filenum >= MAX_PRFILES)
2802         {
2803                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2804                 return;
2805         }
2806         if (pr_files[filenum] == NULL)
2807         {
2808                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2809                 return;
2810         }
2811         FS_Close(pr_files[filenum]);
2812         pr_files[filenum] = NULL;
2813 }
2814
2815 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2816 void PF_fgets(void)
2817 {
2818         int c, end;
2819         static char string[STRINGTEMP_LENGTH];
2820         int filenum = G_FLOAT(OFS_PARM0);
2821         if (filenum < 0 || filenum >= MAX_PRFILES)
2822         {
2823                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2824                 return;
2825         }
2826         if (pr_files[filenum] == NULL)
2827         {
2828                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2829                 return;
2830         }
2831         end = 0;
2832         for (;;)
2833         {
2834                 c = FS_Getc(pr_files[filenum]);
2835                 if (c == '\r' || c == '\n' || c < 0)
2836                         break;
2837                 if (end < STRINGTEMP_LENGTH - 1)
2838                         string[end++] = c;
2839         }
2840         string[end] = 0;
2841         // remove \n following \r
2842         if (c == '\r')
2843                 c = FS_Getc(pr_files[filenum]);
2844         if (developer.integer)
2845                 Con_Printf("fgets: %s\n", string);
2846         if (c >= 0)
2847                 G_INT(OFS_RETURN) = PR_SetString(string);
2848         else
2849                 G_INT(OFS_RETURN) = 0;
2850 }
2851
2852 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2853 void PF_fputs(void)
2854 {
2855         int stringlength;
2856         char string[STRINGTEMP_LENGTH];
2857         int filenum = G_FLOAT(OFS_PARM0);
2858         if (filenum < 0 || filenum >= MAX_PRFILES)
2859         {
2860                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2861                 return;
2862         }
2863         if (pr_files[filenum] == NULL)
2864         {
2865                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2866                 return;
2867         }
2868         PF_VarString(1, string, sizeof(string));
2869         if ((stringlength = strlen(string)))
2870                 FS_Write(pr_files[filenum], string, stringlength);
2871         if (developer.integer)
2872                 Con_Printf("fputs: %s\n", string);
2873 }
2874
2875 //float(string s) strlen = #114; // returns how many characters are in a string
2876 void PF_strlen(void)
2877 {
2878         char *s;
2879         s = G_STRING(OFS_PARM0);
2880         if (s)
2881                 G_FLOAT(OFS_RETURN) = strlen(s);
2882         else
2883                 G_FLOAT(OFS_RETURN) = 0;
2884 }
2885
2886 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2887 void PF_strcat(void)
2888 {
2889         char *s = PR_GetTempString();
2890         PF_VarString(0, s, STRINGTEMP_LENGTH);
2891         G_INT(OFS_RETURN) = PR_SetString(s);
2892 }
2893
2894 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2895 void PF_substring(void)
2896 {
2897         int i, start, length;
2898         char *s, *string = PR_GetTempString();
2899         s = G_STRING(OFS_PARM0);
2900         start = G_FLOAT(OFS_PARM1);
2901         length = G_FLOAT(OFS_PARM2);
2902         if (!s)
2903                 s = "";
2904         for (i = 0;i < start && *s;i++, s++);
2905         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2906                 string[i] = *s;
2907         string[i] = 0;
2908         G_INT(OFS_RETURN) = PR_SetString(string);
2909 }
2910
2911 //vector(string s) stov = #117; // returns vector value from a string
2912 void PF_stov(void)
2913 {
2914         char string[STRINGTEMP_LENGTH];
2915         PF_VarString(0, string, sizeof(string));
2916         Math_atov(string, G_VECTOR(OFS_RETURN));
2917 }
2918
2919 //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
2920 void PF_strzone(void)
2921 {
2922         char *in, *out;
2923         in = G_STRING(OFS_PARM0);
2924         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2925         strcpy(out, in);
2926         G_INT(OFS_RETURN) = PR_SetString(out);
2927 }
2928
2929 //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
2930 void PF_strunzone(void)
2931 {
2932         Mem_Free(G_STRING(OFS_PARM0));
2933 }
2934
2935 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2936 //this function originally written by KrimZon, made shorter by LordHavoc
2937 void PF_clientcommand (void)
2938 {
2939         client_t *temp_client;
2940         int i;
2941
2942         //find client for this entity
2943         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2944         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2945         {
2946                 Con_Printf("PF_clientcommand: entity is not a client");
2947                 return;
2948         }
2949
2950         temp_client = host_client;
2951         host_client = svs.clients + i;
2952         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2953         host_client = temp_client;
2954 }
2955
2956 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2957 //this function originally written by KrimZon, made shorter by LordHavoc
2958 char **tokens = NULL;
2959 int    max_tokens, num_tokens = 0;
2960 void PF_tokenize (void)
2961 {
2962         const char *p;
2963         char *str;
2964         str = G_STRING(OFS_PARM0);
2965
2966         if (tokens != NULL)
2967         {
2968                 int i;
2969                 for (i=0;i<num_tokens;i++)
2970                         Z_Free(tokens[i]);
2971                 Z_Free(tokens);
2972                 num_tokens = 0;
2973         }
2974
2975         tokens = Z_Malloc(strlen(str) * sizeof(char *));
2976         max_tokens = strlen(str);
2977
2978         for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2979         {
2980                 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2981                 strcpy(tokens[num_tokens], com_token);
2982         }
2983
2984         G_FLOAT(OFS_RETURN) = num_tokens;
2985 }
2986
2987 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2988 //this function originally written by KrimZon, made shorter by LordHavoc
2989 void PF_argv (void)
2990 {
2991         int token_num = G_FLOAT(OFS_PARM0);
2992         if (token_num >= 0 && token_num < num_tokens)
2993                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2994         else
2995                 G_INT(OFS_RETURN) = PR_SetString("");
2996 }
2997
2998 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
2999 void PF_setattachment (void)
3000 {
3001         edict_t *e = G_EDICT(OFS_PARM0);
3002         edict_t *tagentity = G_EDICT(OFS_PARM1);
3003         char *tagname = G_STRING(OFS_PARM2);
3004         eval_t *v;
3005         int i, modelindex;
3006         model_t *model;
3007
3008         if (e == sv.edicts)
3009                 Host_Error("setattachment: can not modify world entity\n");
3010         if (e->e->free)
3011                 Host_Error("setattachment: can not modify free entity\n");
3012
3013         if (tagentity == NULL)
3014                 tagentity = sv.edicts;
3015
3016         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3017         if (v)
3018                 v->edict = EDICT_TO_PROG(tagentity);
3019
3020         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3021         if (v)
3022                 v->_float = 0;
3023         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3024         {
3025                 modelindex = (int)tagentity->v->modelindex;
3026                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3027                 {
3028                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3029                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3030                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3031                                                 v->_float = i + 1;
3032                         if (v->_float == 0 && model->alias.aliasnum_tags)
3033                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3034                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3035                                                 v->_float = i + 1;
3036                         if (v->_float == 0)
3037                                 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", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
3038                 }
3039                 else
3040                         Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
3041         }
3042 }
3043
3044
3045 builtin_t pr_builtin[] =
3046 {
3047 NULL,                                           // #0
3048 PF_makevectors,                         // #1 void(entity e) makevectors
3049 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3050 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3051 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3052 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3053 PF_break,                                       // #6 void() break
3054 PF_random,                                      // #7 float() random
3055 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3056 PF_normalize,                           // #9 vector(vector v) normalize
3057 PF_error,                                       // #10 void(string e) error
3058 PF_objerror,                            // #11 void(string e) objerror
3059 PF_vlen,                                        // #12 float(vector v) vlen
3060 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3061 PF_Spawn,                                       // #14 entity() spawn
3062 PF_Remove,                                      // #15 void(entity e) remove
3063 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3064 PF_checkclient,                         // #17 entity() clientlist
3065 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3066 PF_precache_sound,                      // #19 void(string s) precache_sound
3067 PF_precache_model,                      // #20 void(string s) precache_model
3068 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3069 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3070 PF_bprint,                                      // #23 void(string s) bprint
3071 PF_sprint,                                      // #24 void(entity client, string s) sprint
3072 PF_dprint,                                      // #25 void(string s) dprint
3073 PF_ftos,                                        // #26 void(string s) ftos
3074 PF_vtos,                                        // #27 void(string s) vtos
3075 PF_coredump,                            // #28 void() coredump
3076 PF_traceon,                                     // #29 void() traceon
3077 PF_traceoff,                            // #30 void() traceoff
3078 PF_eprint,                                      // #31 void(entity e) eprint
3079 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3080 NULL,                                           // #33
3081 PF_droptofloor,                         // #34 float() droptofloor
3082 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3083 PF_rint,                                        // #36 float(float v) rint
3084 PF_floor,                                       // #37 float(float v) floor
3085 PF_ceil,                                        // #38 float(float v) ceil
3086 NULL,                                           // #39
3087 PF_checkbottom,                         // #40 float(entity e) checkbottom
3088 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3089 NULL,                                           // #42
3090 PF_fabs,                                        // #43 float(float f) fabs
3091 PF_aim,                                         // #44 vector(entity e, float speed) aim
3092 PF_cvar,                                        // #45 float(string s) cvar
3093 PF_localcmd,                            // #46 void(string s) localcmd
3094 PF_nextent,                                     // #47 entity(entity e) nextent
3095 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3096 PF_changeyaw,                           // #49 void() ChangeYaw
3097 NULL,                                           // #50
3098 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3099 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3100 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3101 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3102 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3103 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3104 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3105 PF_WriteString,                         // #58 void(float to, string s) WriteString
3106 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3107 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3108 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3109 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3110 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3111 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3112 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3113 NULL,                                           // #66
3114 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3115 PF_precache_file,                       // #68 string(string s) precache_file
3116 PF_makestatic,                          // #69 void(entity e) makestatic
3117 PF_changelevel,                         // #70 void(string s) changelevel
3118 NULL,                                           // #71
3119 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3120 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3121 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3122 PF_precache_model,                      // #75 string(string s) precache_model2
3123 PF_precache_sound,                      // #76 string(string s) precache_sound2
3124 PF_precache_file,                       // #77 string(string s) precache_file2
3125 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3126 NULL,                                           // #79
3127 NULL,                                           // #80
3128 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3129 NULL,                                           // #82
3130 NULL,                                           // #83
3131 NULL,                                           // #84
3132 NULL,                                           // #85
3133 NULL,                                           // #86
3134 NULL,                                           // #87
3135 NULL,                                           // #88
3136 NULL,                                           // #89
3137 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3138 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3139 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3140 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3141 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3142 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3143 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3144 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3145 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3146 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3147 NULL,                                           // #100
3148 NULL,                                           // #101
3149 NULL,                                           // #102
3150 NULL,                                           // #103
3151 NULL,                                           // #104
3152 NULL,                                           // #105
3153 NULL,                                           // #106
3154 NULL,                                           // #107
3155 NULL,                                           // #108
3156 NULL,                                           // #109
3157 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3158 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3159 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3160 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3161 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3162 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3163 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3164 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3165 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3166 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3167 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3168 a a a a a a a a                         // #120-199
3169 a a a a a a a a a a                     // #200-299
3170 a a a a a a a a a a                     // #300-399
3171 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3172 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3173 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3174 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3175 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3176 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3177 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3178 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3179 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3180 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3181 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3182 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3183 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3184 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3185 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3186 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3187 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3188 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3189 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3190 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3191 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3192 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3193 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3194 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3195 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3196 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3197 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3198 PF_te_explosion2,                       // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3199 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3200 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3201 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3202 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3203 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3204 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3205 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3206 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3207 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3208 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3209 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3210 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3211 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3212 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3213 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3214 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3215 NULL,                                           // #444
3216 NULL,                                           // #445
3217 NULL,                                           // #446
3218 NULL,                                           // #447
3219 NULL,                                           // #448
3220 NULL,                                           // #449
3221 a a a a a                                       // #450-499 (LordHavoc)
3222 };
3223
3224 builtin_t *pr_builtins = pr_builtin;
3225 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3226
3227 void PR_Cmd_Init(void)
3228 {
3229         pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3230         PR_Files_Init();
3231 }
3232
3233 void PR_Cmd_Reset(void)
3234 {
3235         Mem_EmptyPool(pr_strings_mempool);
3236         PR_Files_CloseAll();
3237 }
3238