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