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