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