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