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