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