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