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