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