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