]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
*** empty log message ***
[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 }
2508
2509 void PF_te_lightning1 (void)
2510 {
2511         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2512         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2513         // owner entity
2514         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2515         // start
2516         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2517         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2518         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2519         // end
2520         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2521         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2522         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2523 }
2524
2525 void PF_te_lightning2 (void)
2526 {
2527         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2528         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2529         // owner entity
2530         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2531         // start
2532         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2533         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2534         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2535         // end
2536         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2537         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2538         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2539 }
2540
2541 void PF_te_lightning3 (void)
2542 {
2543         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2544         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2545         // owner entity
2546         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2547         // start
2548         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2549         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2550         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2551         // end
2552         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2553         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2554         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2555 }
2556
2557 void PF_te_beam (void)
2558 {
2559         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2560         MSG_WriteByte(&sv.datagram, TE_BEAM);
2561         // owner entity
2562         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2563         // start
2564         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2565         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2566         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2567         // end
2568         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2569         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2570         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2571 }
2572
2573 void PF_te_plasmaburn (void)
2574 {
2575         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2576         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2577         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2578         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2579         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2580 }
2581
2582 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2583 {
2584         int i, j;
2585         vec3_t v1, clipplanenormal, normal;
2586         vec_t clipplanedist, clipdist;
2587         VectorCopy(p, out);
2588         if (surf->flags & SURF_PLANEBACK)
2589                 VectorNegate(surf->plane->normal, normal);
2590         else
2591                 VectorCopy(surf->plane->normal, normal);
2592         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2593         {
2594                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2595                 VectorNormalizeFast(v1);
2596                 CrossProduct(v1, normal, clipplanenormal);
2597                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2598                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2599                 if (clipdist > 0)
2600                 {
2601                         clipdist = -clipdist;
2602                         VectorMA(out, clipdist, clipplanenormal, out);
2603                 }
2604         }
2605 }
2606
2607 static msurface_t *getsurface(edict_t *ed, int surfnum)
2608 {
2609         int modelindex;
2610         model_t *model;
2611         if (!ed || ed->e->free)
2612                 return NULL;
2613         modelindex = ed->v->modelindex;
2614         if (modelindex < 1 || modelindex >= MAX_MODELS)
2615                 return NULL;
2616         model = sv.models[modelindex];
2617         if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2618                 return NULL;
2619         return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2620 }
2621
2622
2623 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2624 void PF_getsurfacenumpoints(void)
2625 {
2626         msurface_t *surf;
2627         // return 0 if no such surface
2628         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2629         {
2630                 G_FLOAT(OFS_RETURN) = 0;
2631                 return;
2632         }
2633
2634         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2635 }
2636 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2637 void PF_getsurfacepoint(void)
2638 {
2639         edict_t *ed;
2640         msurface_t *surf;
2641         int pointnum;
2642         VectorClear(G_VECTOR(OFS_RETURN));
2643         ed = G_EDICT(OFS_PARM0);
2644         if (!ed || ed->e->free)
2645                 return;
2646         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2647                 return;
2648         pointnum = G_FLOAT(OFS_PARM2);
2649         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2650                 return;
2651         // FIXME: implement rotation/scaling
2652         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2653 }
2654 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2655 void PF_getsurfacenormal(void)
2656 {
2657         msurface_t *surf;
2658         VectorClear(G_VECTOR(OFS_RETURN));
2659         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2660                 return;
2661         // FIXME: implement rotation/scaling
2662         if (surf->flags & SURF_PLANEBACK)
2663                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2664         else
2665                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2666 }
2667 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2668 void PF_getsurfacetexture(void)
2669 {
2670         msurface_t *surf;
2671         G_INT(OFS_RETURN) = 0;
2672         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2673                 return;
2674         G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2675 }
2676 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2677 void PF_getsurfacenearpoint(void)
2678 {
2679         int surfnum, best, modelindex;
2680         vec3_t clipped, p;
2681         vec_t dist, bestdist;
2682         edict_t *ed;
2683         model_t *model;
2684         msurface_t *surf;
2685         vec_t *point;
2686         G_FLOAT(OFS_RETURN) = -1;
2687         ed = G_EDICT(OFS_PARM0);
2688         point = G_VECTOR(OFS_PARM1);
2689
2690         if (!ed || ed->e->free)
2691                 return;
2692         modelindex = ed->v->modelindex;
2693         if (modelindex < 1 || modelindex >= MAX_MODELS)
2694                 return;
2695         model = sv.models[modelindex];
2696         if (!model->brushq1.numsurfaces)
2697                 return;
2698
2699         // FIXME: implement rotation/scaling
2700         VectorSubtract(point, ed->v->origin, p);
2701         best = -1;
2702         bestdist = 1000000000;
2703         for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2704         {
2705                 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2706                 dist = PlaneDiff(p, surf->plane);
2707                 dist = dist * dist;
2708                 if (dist < bestdist)
2709                 {
2710                         clippointtosurface(surf, p, clipped);
2711                         VectorSubtract(clipped, p, clipped);
2712                         dist += DotProduct(clipped, clipped);
2713                         if (dist < bestdist)
2714                         {
2715                                 best = surfnum;
2716                                 bestdist = dist;
2717                         }
2718                 }
2719         }
2720         G_FLOAT(OFS_RETURN) = best;
2721 }
2722 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2723 void PF_getsurfaceclippedpoint(void)
2724 {
2725         edict_t *ed;
2726         msurface_t *surf;
2727         vec3_t p, out;
2728         VectorClear(G_VECTOR(OFS_RETURN));
2729         ed = G_EDICT(OFS_PARM0);
2730         if (!ed || ed->e->free)
2731                 return;
2732         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2733                 return;
2734         // FIXME: implement rotation/scaling
2735         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2736         clippointtosurface(surf, p, out);
2737         // FIXME: implement rotation/scaling
2738         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2739 }
2740
2741 #define MAX_PRFILES 256
2742
2743 qfile_t *pr_files[MAX_PRFILES];
2744
2745 void PR_Files_Init(void)
2746 {
2747         memset(pr_files, 0, sizeof(pr_files));
2748 }
2749
2750 void PR_Files_CloseAll(void)
2751 {
2752         int i;
2753         for (i = 0;i < MAX_PRFILES;i++)
2754         {
2755                 if (pr_files[i])
2756                         FS_Close(pr_files[i]);
2757                 pr_files[i] = NULL;
2758         }
2759 }
2760
2761 //float(string s) stof = #81; // get numerical value from a string
2762 void PF_stof(void)
2763 {
2764         char string[STRINGTEMP_LENGTH];
2765         PF_VarString(0, string, sizeof(string));
2766         G_FLOAT(OFS_RETURN) = atof(string);
2767 }
2768
2769 //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
2770 void PF_fopen(void)
2771 {
2772         int filenum, mode, i;
2773         char *modestring, *filename;
2774         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2775                 if (pr_files[filenum] == NULL)
2776                         break;
2777         if (filenum >= MAX_PRFILES)
2778         {
2779                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2780                 G_FLOAT(OFS_RETURN) = -2;
2781                 return;
2782         }
2783         mode = G_FLOAT(OFS_PARM1);
2784         switch(mode)
2785         {
2786         case 0: // FILE_READ
2787                 modestring = "rb";
2788                 break;
2789         case 1: // FILE_APPEND
2790                 modestring = "ab";
2791                 break;
2792         case 2: // FILE_WRITE
2793                 modestring = "wb";
2794                 break;
2795         default:
2796                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2797                 G_FLOAT(OFS_RETURN) = -3;
2798                 return;
2799         }
2800         filename = G_STRING(OFS_PARM0);
2801         // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2802         // ../ is parent directory on many platforms
2803         // // is parent directory on Amiga
2804         // / at the beginning of a path is root on unix, and parent directory on Amiga
2805         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2806         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2807         for (i = 0;filename[i];i++)
2808         {
2809                 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2810                 {
2811                         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);
2812                         G_FLOAT(OFS_RETURN) = -4;
2813                         return;
2814                 }
2815         }
2816         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2817
2818         if (pr_files[filenum] == NULL && modestring == "rb")
2819                 pr_files[filenum] = FS_Open(filename, modestring, false);
2820
2821         if (pr_files[filenum] == NULL)
2822                 G_FLOAT(OFS_RETURN) = -1;
2823         else
2824                 G_FLOAT(OFS_RETURN) = filenum;
2825 }
2826
2827 //void(float fhandle) fclose = #111; // closes a file
2828 void PF_fclose(void)
2829 {
2830         int filenum = G_FLOAT(OFS_PARM0);
2831         if (filenum < 0 || filenum >= MAX_PRFILES)
2832         {
2833                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2834                 return;
2835         }
2836         if (pr_files[filenum] == NULL)
2837         {
2838                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2839                 return;
2840         }
2841         FS_Close(pr_files[filenum]);
2842         pr_files[filenum] = NULL;
2843 }
2844
2845 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2846 void PF_fgets(void)
2847 {
2848         int c, end;
2849         static char string[STRINGTEMP_LENGTH];
2850         int filenum = G_FLOAT(OFS_PARM0);
2851         if (filenum < 0 || filenum >= MAX_PRFILES)
2852         {
2853                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2854                 return;
2855         }
2856         if (pr_files[filenum] == NULL)
2857         {
2858                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2859                 return;
2860         }
2861         end = 0;
2862         for (;;)
2863         {
2864                 c = FS_Getc(pr_files[filenum]);
2865                 if (c == '\r' || c == '\n' || c < 0)
2866                         break;
2867                 if (end < STRINGTEMP_LENGTH - 1)
2868                         string[end++] = c;
2869         }
2870         string[end] = 0;
2871         // remove \n following \r
2872         if (c == '\r')
2873                 c = FS_Getc(pr_files[filenum]);
2874         if (developer.integer)
2875                 Con_Printf("fgets: %s\n", string);
2876         if (c >= 0)
2877                 G_INT(OFS_RETURN) = PR_SetString(string);
2878         else
2879                 G_INT(OFS_RETURN) = 0;
2880 }
2881
2882 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2883 void PF_fputs(void)
2884 {
2885         int stringlength;
2886         char string[STRINGTEMP_LENGTH];
2887         int filenum = G_FLOAT(OFS_PARM0);
2888         if (filenum < 0 || filenum >= MAX_PRFILES)
2889         {
2890                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2891                 return;
2892         }
2893         if (pr_files[filenum] == NULL)
2894         {
2895                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2896                 return;
2897         }
2898         PF_VarString(1, string, sizeof(string));
2899         if ((stringlength = strlen(string)))
2900                 FS_Write(pr_files[filenum], string, stringlength);
2901         if (developer.integer)
2902                 Con_Printf("fputs: %s\n", string);
2903 }
2904
2905 //float(string s) strlen = #114; // returns how many characters are in a string
2906 void PF_strlen(void)
2907 {
2908         char *s;
2909         s = G_STRING(OFS_PARM0);
2910         if (s)
2911                 G_FLOAT(OFS_RETURN) = strlen(s);
2912         else
2913                 G_FLOAT(OFS_RETURN) = 0;
2914 }
2915
2916 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2917 void PF_strcat(void)
2918 {
2919         char *s = PR_GetTempString();
2920         PF_VarString(0, s, STRINGTEMP_LENGTH);
2921         G_INT(OFS_RETURN) = PR_SetString(s);
2922 }
2923
2924 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2925 void PF_substring(void)
2926 {
2927         int i, start, length;
2928         char *s, *string = PR_GetTempString();
2929         s = G_STRING(OFS_PARM0);
2930         start = G_FLOAT(OFS_PARM1);
2931         length = G_FLOAT(OFS_PARM2);
2932         if (!s)
2933                 s = "";
2934         for (i = 0;i < start && *s;i++, s++);
2935         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2936                 string[i] = *s;
2937         string[i] = 0;
2938         G_INT(OFS_RETURN) = PR_SetString(string);
2939 }
2940
2941 //vector(string s) stov = #117; // returns vector value from a string
2942 void PF_stov(void)
2943 {
2944         char string[STRINGTEMP_LENGTH];
2945         PF_VarString(0, string, sizeof(string));
2946         Math_atov(string, G_VECTOR(OFS_RETURN));
2947 }
2948
2949 //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)
2950 void PF_strzone(void)
2951 {
2952         char *in, *out;
2953         in = G_STRING(OFS_PARM0);
2954         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2955         strcpy(out, in);
2956         G_INT(OFS_RETURN) = PR_SetString(out);
2957 }
2958
2959 //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!!!)
2960 void PF_strunzone(void)
2961 {
2962         Mem_Free(G_STRING(OFS_PARM0));
2963 }
2964
2965 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2966 //this function originally written by KrimZon, made shorter by LordHavoc
2967 void PF_clientcommand (void)
2968 {
2969         client_t *temp_client;
2970         int i;
2971
2972         //find client for this entity
2973         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2974         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2975         {
2976                 Con_Print("PF_clientcommand: entity is not a client\n");
2977                 return;
2978         }
2979
2980         temp_client = host_client;
2981         host_client = svs.clients + i;
2982         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2983         host_client = temp_client;
2984 }
2985
2986 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2987 //this function originally written by KrimZon, made shorter by LordHavoc
2988 //20040203: rewritten by LordHavoc (no longer uses allocations)
2989 int num_tokens = 0;
2990 char *tokens[256], tokenbuf[4096];
2991 void PF_tokenize (void)
2992 {
2993         int pos;
2994         const char *p;
2995         p = G_STRING(OFS_PARM0);
2996
2997         num_tokens = 0;
2998         pos = 0;
2999         while(COM_ParseToken(&p, false))
3000         {
3001                 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3002                         break;
3003                 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3004                         break;
3005                 tokens[num_tokens++] = tokenbuf + pos;
3006                 strcpy(tokenbuf + pos, com_token);
3007                 pos += strlen(com_token) + 1;
3008         }
3009
3010         G_FLOAT(OFS_RETURN) = num_tokens;
3011 }
3012
3013 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3014 //this function originally written by KrimZon, made shorter by LordHavoc
3015 void PF_argv (void)
3016 {
3017         int token_num = G_FLOAT(OFS_PARM0);
3018         if (token_num >= 0 && token_num < num_tokens)
3019                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3020         else
3021                 G_INT(OFS_RETURN) = PR_SetString("");
3022 }
3023
3024 //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)
3025 void PF_setattachment (void)
3026 {
3027         edict_t *e = G_EDICT(OFS_PARM0);
3028         edict_t *tagentity = G_EDICT(OFS_PARM1);
3029         char *tagname = G_STRING(OFS_PARM2);
3030         eval_t *v;
3031         int i, modelindex;
3032         model_t *model;
3033
3034         if (e == sv.edicts)
3035                 PF_WARNING("setattachment: can not modify world entity\n");
3036         if (e->e->free)
3037                 PF_WARNING("setattachment: can not modify free entity\n");
3038
3039         if (tagentity == NULL)
3040                 tagentity = sv.edicts;
3041
3042         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3043         if (v)
3044                 v->edict = EDICT_TO_PROG(tagentity);
3045
3046         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3047         if (v)
3048                 v->_float = 0;
3049         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3050         {
3051                 modelindex = (int)tagentity->v->modelindex;
3052                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3053                 {
3054                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3055                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3056                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3057                                                 v->_float = i + 1;
3058                         if (v->_float == 0 && model->alias.aliasnum_tags)
3059                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3060                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3061                                                 v->_float = i + 1;
3062                         if (v->_float == 0)
3063                                 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);
3064                 }
3065                 else
3066                         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));
3067         }
3068 }
3069
3070
3071 /////////////////////////////////////////
3072 // DP_QC_FS_SEARCH extension
3073
3074 // qc fs search handling
3075 #define MAX_SEARCHES 128
3076
3077 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3078
3079 void PR_Search_Init(void)
3080 {
3081         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3082 }
3083
3084 void PR_Search_Reset(void)
3085 {
3086         int i;
3087         // reset the fssearch list
3088         for(i = 0; i < MAX_SEARCHES; i++)
3089                 if(pr_fssearchlist[i])
3090                         FS_FreeSearch(pr_fssearchlist[i]);
3091         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3092 }
3093
3094 /*
3095 =========
3096 PF_search_begin
3097
3098 float search_begin(string pattern, float caseinsensitive, float quiet)
3099 =========
3100 */
3101 void PF_search_begin(void)
3102 {
3103         int handle;
3104         char *pattern;
3105         int caseinsens, quiet;
3106
3107         pattern = G_STRING(OFS_PARM0);
3108
3109         PR_CheckEmptyString(pattern);
3110
3111         caseinsens = G_FLOAT(OFS_PARM1);
3112         quiet = G_FLOAT(OFS_PARM2);
3113         
3114         for(handle = 0; handle < MAX_SEARCHES; handle++)
3115                 if(!pr_fssearchlist[handle])
3116                         break;
3117
3118         if(handle >= MAX_SEARCHES)
3119         {
3120                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3121                 G_FLOAT(OFS_RETURN) = -2;
3122                 return;
3123         }
3124
3125         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3126                 G_FLOAT(OFS_RETURN) = -1;
3127         else
3128                 G_FLOAT(OFS_RETURN) = handle;
3129 }
3130
3131 /*
3132 =========
3133 VM_search_end
3134
3135 void    search_end(float handle)
3136 =========
3137 */
3138 void PF_search_end(void)
3139 {
3140         int handle;
3141
3142         handle = G_FLOAT(OFS_PARM0);
3143         
3144         if(handle < 0 || handle >= MAX_SEARCHES)
3145         {
3146                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3147                 return;
3148         }
3149         if(pr_fssearchlist[handle] == NULL)
3150         {
3151                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3152                 return;
3153         }
3154
3155         FS_FreeSearch(pr_fssearchlist[handle]);
3156         pr_fssearchlist[handle] = NULL;
3157 }
3158
3159 /*
3160 =========
3161 VM_search_getsize
3162
3163 float   search_getsize(float handle)
3164 =========
3165 */
3166 void PF_search_getsize(void)
3167 {
3168         int handle;
3169
3170         handle = G_FLOAT(OFS_PARM0);
3171
3172         if(handle < 0 || handle >= MAX_SEARCHES)
3173         {
3174                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3175                 return;
3176         }
3177         if(pr_fssearchlist[handle] == NULL)
3178         {
3179                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3180                 return;
3181         }
3182         
3183         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3184 }
3185
3186 /*
3187 =========
3188 VM_search_getfilename
3189
3190 string  search_getfilename(float handle, float num)
3191 =========
3192 */
3193 void PF_search_getfilename(void)
3194 {
3195         int handle, filenum;
3196         char *tmp;
3197
3198         handle = G_FLOAT(OFS_PARM0);
3199         filenum = G_FLOAT(OFS_PARM1);
3200
3201         if(handle < 0 || handle >= MAX_SEARCHES)
3202         {
3203                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3204                 return;
3205         }
3206         if(pr_fssearchlist[handle] == NULL)
3207         {
3208                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3209                 return;
3210         }
3211         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3212         {
3213                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3214                 return;
3215         }
3216         
3217         tmp = PR_GetTempString();
3218         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3219
3220         G_INT(OFS_RETURN) = PR_SetString(tmp);
3221 }
3222
3223 void PF_cvar_string (void)
3224 {
3225         char *str;
3226         cvar_t *var;
3227         char *tmp;
3228
3229         str = G_STRING(OFS_PARM0);
3230         var = Cvar_FindVar (str);
3231
3232         tmp = PR_GetTempString();
3233         strcpy(tmp, var->string);
3234
3235         G_INT(OFS_RETURN) = PR_SetString(tmp);
3236 }
3237
3238
3239
3240 builtin_t pr_builtin[] =
3241 {
3242 NULL,                                           // #0
3243 PF_makevectors,                         // #1 void(entity e) makevectors
3244 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3245 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3246 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3247 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3248 PF_break,                                       // #6 void() break
3249 PF_random,                                      // #7 float() random
3250 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3251 PF_normalize,                           // #9 vector(vector v) normalize
3252 PF_error,                                       // #10 void(string e) error
3253 PF_objerror,                            // #11 void(string e) objerror
3254 PF_vlen,                                        // #12 float(vector v) vlen
3255 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3256 PF_Spawn,                                       // #14 entity() spawn
3257 PF_Remove,                                      // #15 void(entity e) remove
3258 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3259 PF_checkclient,                         // #17 entity() clientlist
3260 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3261 PF_precache_sound,                      // #19 void(string s) precache_sound
3262 PF_precache_model,                      // #20 void(string s) precache_model
3263 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3264 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3265 PF_bprint,                                      // #23 void(string s) bprint
3266 PF_sprint,                                      // #24 void(entity client, string s) sprint
3267 PF_dprint,                                      // #25 void(string s) dprint
3268 PF_ftos,                                        // #26 void(string s) ftos
3269 PF_vtos,                                        // #27 void(string s) vtos
3270 PF_coredump,                            // #28 void() coredump
3271 PF_traceon,                                     // #29 void() traceon
3272 PF_traceoff,                            // #30 void() traceoff
3273 PF_eprint,                                      // #31 void(entity e) eprint
3274 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3275 NULL,                                           // #33
3276 PF_droptofloor,                         // #34 float() droptofloor
3277 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3278 PF_rint,                                        // #36 float(float v) rint
3279 PF_floor,                                       // #37 float(float v) floor
3280 PF_ceil,                                        // #38 float(float v) ceil
3281 NULL,                                           // #39
3282 PF_checkbottom,                         // #40 float(entity e) checkbottom
3283 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3284 NULL,                                           // #42
3285 PF_fabs,                                        // #43 float(float f) fabs
3286 PF_aim,                                         // #44 vector(entity e, float speed) aim
3287 PF_cvar,                                        // #45 float(string s) cvar
3288 PF_localcmd,                            // #46 void(string s) localcmd
3289 PF_nextent,                                     // #47 entity(entity e) nextent
3290 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3291 PF_changeyaw,                           // #49 void() ChangeYaw
3292 NULL,                                           // #50
3293 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3294 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3295 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3296 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3297 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3298 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3299 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3300 PF_WriteString,                         // #58 void(float to, string s) WriteString
3301 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3302 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3303 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3304 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3305 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3306 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3307 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3308 NULL,                                           // #66
3309 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3310 PF_precache_file,                       // #68 string(string s) precache_file
3311 PF_makestatic,                          // #69 void(entity e) makestatic
3312 PF_changelevel,                         // #70 void(string s) changelevel
3313 NULL,                                           // #71
3314 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3315 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3316 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3317 PF_precache_model,                      // #75 string(string s) precache_model2
3318 PF_precache_sound,                      // #76 string(string s) precache_sound2
3319 PF_precache_file,                       // #77 string(string s) precache_file2
3320 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3321 NULL,                                           // #79
3322 NULL,                                           // #80
3323 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3324 NULL,                                           // #82
3325 NULL,                                           // #83
3326 NULL,                                           // #84
3327 NULL,                                           // #85
3328 NULL,                                           // #86
3329 NULL,                                           // #87
3330 NULL,                                           // #88
3331 NULL,                                           // #89
3332 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3333 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3334 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3335 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3336 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3337 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3338 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3339 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3340 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3341 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3342 NULL,                                           // #100
3343 NULL,                                           // #101
3344 NULL,                                           // #102
3345 NULL,                                           // #103
3346 NULL,                                           // #104
3347 NULL,                                           // #105
3348 NULL,                                           // #106
3349 NULL,                                           // #107
3350 NULL,                                           // #108
3351 NULL,                                           // #109
3352 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3353 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3354 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3355 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3356 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3357 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3358 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3359 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3360 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3361 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3362 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3363 a a a a a a a a                         // #120-199
3364 a a a a a a a a a a                     // #200-299
3365 a a a a a a a a a a                     // #300-399
3366 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3367 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3368 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3369 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3370 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3371 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3372 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3373 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3374 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3375 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3376 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3377 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3378 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3379 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3380 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3381 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3382 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3383 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3384 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3385 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3386 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3387 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3388 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3389 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3390 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3391 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3392 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3393 PF_te_explosion2,                       // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3394 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3395 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3396 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3397 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3398 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3399 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3400 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3401 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3402 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3403 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3404 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3405 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3406 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3407 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3408 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3409 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3410 PF_search_begin,                        // #444
3411 PF_search_end,                          // #445
3412 PF_search_getsize,                      // #446
3413 PF_search_getfilename,          // #447
3414 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3415 NULL,                                           // #449
3416 a a a a a                                       // #450-499 (LordHavoc)
3417 };
3418
3419 builtin_t *pr_builtins = pr_builtin;
3420 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3421
3422 void PR_Cmd_Init(void)
3423 {
3424         pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3425         PR_Files_Init();
3426         PR_Search_Init();
3427 }
3428
3429 void PR_Cmd_Reset(void)
3430 {
3431         Mem_EmptyPool(pr_strings_mempool);
3432         PR_Search_Reset();
3433         PR_Files_CloseAll();
3434 }
3435