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