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