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