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