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