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