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