]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
made gl_texture_anisotropy take effect immediately like gl_texturemode rather than...
[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, i;
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         // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2798         // ../ is parent directory on many platforms
2799         // // is parent directory on Amiga
2800         // / at the beginning of a path is root on unix, and parent directory on Amiga
2801         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2802         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2803         for (i = 0;filename[i];i++)
2804         {
2805                 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2806                 {
2807                         Con_Printf("PF_fopen: dangerous/confusing/annoying/non-portable filename \"%s\" not allowed. (contains control characters or // or .. or : or \\ or begins with /)\n", filename);
2808                         G_FLOAT(OFS_RETURN) = -4;
2809                         return;
2810                 }
2811         }
2812         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2813
2814         if (pr_files[filenum] == NULL && modestring == "rb")
2815                 pr_files[filenum] = FS_Open(filename, modestring, false);
2816
2817         if (pr_files[filenum] == NULL)
2818                 G_FLOAT(OFS_RETURN) = -1;
2819         else
2820                 G_FLOAT(OFS_RETURN) = filenum;
2821 }
2822
2823 //void(float fhandle) fclose = #111; // closes a file
2824 void PF_fclose(void)
2825 {
2826         int filenum = G_FLOAT(OFS_PARM0);
2827         if (filenum < 0 || filenum >= MAX_PRFILES)
2828         {
2829                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2830                 return;
2831         }
2832         if (pr_files[filenum] == NULL)
2833         {
2834                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2835                 return;
2836         }
2837         FS_Close(pr_files[filenum]);
2838         pr_files[filenum] = NULL;
2839 }
2840
2841 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2842 void PF_fgets(void)
2843 {
2844         int c, end;
2845         static char string[STRINGTEMP_LENGTH];
2846         int filenum = G_FLOAT(OFS_PARM0);
2847         if (filenum < 0 || filenum >= MAX_PRFILES)
2848         {
2849                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2850                 return;
2851         }
2852         if (pr_files[filenum] == NULL)
2853         {
2854                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2855                 return;
2856         }
2857         end = 0;
2858         for (;;)
2859         {
2860                 c = FS_Getc(pr_files[filenum]);
2861                 if (c == '\r' || c == '\n' || c < 0)
2862                         break;
2863                 if (end < STRINGTEMP_LENGTH - 1)
2864                         string[end++] = c;
2865         }
2866         string[end] = 0;
2867         // remove \n following \r
2868         if (c == '\r')
2869                 c = FS_Getc(pr_files[filenum]);
2870         if (developer.integer)
2871                 Con_Printf("fgets: %s\n", string);
2872         if (c >= 0)
2873                 G_INT(OFS_RETURN) = PR_SetString(string);
2874         else
2875                 G_INT(OFS_RETURN) = 0;
2876 }
2877
2878 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2879 void PF_fputs(void)
2880 {
2881         int stringlength;
2882         char string[STRINGTEMP_LENGTH];
2883         int filenum = G_FLOAT(OFS_PARM0);
2884         if (filenum < 0 || filenum >= MAX_PRFILES)
2885         {
2886                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2887                 return;
2888         }
2889         if (pr_files[filenum] == NULL)
2890         {
2891                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2892                 return;
2893         }
2894         PF_VarString(1, string, sizeof(string));
2895         if ((stringlength = strlen(string)))
2896                 FS_Write(pr_files[filenum], string, stringlength);
2897         if (developer.integer)
2898                 Con_Printf("fputs: %s\n", string);
2899 }
2900
2901 //float(string s) strlen = #114; // returns how many characters are in a string
2902 void PF_strlen(void)
2903 {
2904         char *s;
2905         s = G_STRING(OFS_PARM0);
2906         if (s)
2907                 G_FLOAT(OFS_RETURN) = strlen(s);
2908         else
2909                 G_FLOAT(OFS_RETURN) = 0;
2910 }
2911
2912 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2913 void PF_strcat(void)
2914 {
2915         char *s = PR_GetTempString();
2916         PF_VarString(0, s, STRINGTEMP_LENGTH);
2917         G_INT(OFS_RETURN) = PR_SetString(s);
2918 }
2919
2920 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2921 void PF_substring(void)
2922 {
2923         int i, start, length;
2924         char *s, *string = PR_GetTempString();
2925         s = G_STRING(OFS_PARM0);
2926         start = G_FLOAT(OFS_PARM1);
2927         length = G_FLOAT(OFS_PARM2);
2928         if (!s)
2929                 s = "";
2930         for (i = 0;i < start && *s;i++, s++);
2931         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2932                 string[i] = *s;
2933         string[i] = 0;
2934         G_INT(OFS_RETURN) = PR_SetString(string);
2935 }
2936
2937 //vector(string s) stov = #117; // returns vector value from a string
2938 void PF_stov(void)
2939 {
2940         char string[STRINGTEMP_LENGTH];
2941         PF_VarString(0, string, sizeof(string));
2942         Math_atov(string, G_VECTOR(OFS_RETURN));
2943 }
2944
2945 //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)
2946 void PF_strzone(void)
2947 {
2948         char *in, *out;
2949         in = G_STRING(OFS_PARM0);
2950         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2951         strcpy(out, in);
2952         G_INT(OFS_RETURN) = PR_SetString(out);
2953 }
2954
2955 //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!!!)
2956 void PF_strunzone(void)
2957 {
2958         Mem_Free(G_STRING(OFS_PARM0));
2959 }
2960
2961 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2962 //this function originally written by KrimZon, made shorter by LordHavoc
2963 void PF_clientcommand (void)
2964 {
2965         client_t *temp_client;
2966         int i;
2967
2968         //find client for this entity
2969         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2970         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2971         {
2972                 Con_Print("PF_clientcommand: entity is not a client\n");
2973                 return;
2974         }
2975
2976         temp_client = host_client;
2977         host_client = svs.clients + i;
2978         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2979         host_client = temp_client;
2980 }
2981
2982 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2983 //this function originally written by KrimZon, made shorter by LordHavoc
2984 //20040203: rewritten by LordHavoc (no longer uses allocations)
2985 int num_tokens = 0;
2986 char *tokens[256], tokenbuf[4096];
2987 void PF_tokenize (void)
2988 {
2989         int pos;
2990         const char *p;
2991         p = G_STRING(OFS_PARM0);
2992
2993         num_tokens = 0;
2994         pos = 0;
2995         while(COM_ParseToken(&p, false))
2996         {
2997                 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
2998                         break;
2999                 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3000                         break;
3001                 tokens[num_tokens++] = tokenbuf + pos;
3002                 strcpy(tokenbuf + pos, com_token);
3003                 pos += strlen(com_token) + 1;
3004         }
3005
3006         G_FLOAT(OFS_RETURN) = num_tokens;
3007 }
3008
3009 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3010 //this function originally written by KrimZon, made shorter by LordHavoc
3011 void PF_argv (void)
3012 {
3013         int token_num = G_FLOAT(OFS_PARM0);
3014         if (token_num >= 0 && token_num < num_tokens)
3015                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3016         else
3017                 G_INT(OFS_RETURN) = PR_SetString("");
3018 }
3019
3020 //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)
3021 void PF_setattachment (void)
3022 {
3023         edict_t *e = G_EDICT(OFS_PARM0);
3024         edict_t *tagentity = G_EDICT(OFS_PARM1);
3025         char *tagname = G_STRING(OFS_PARM2);
3026         eval_t *v;
3027         int i, modelindex;
3028         model_t *model;
3029
3030         if (e == sv.edicts)
3031                 PF_WARNING("setattachment: can not modify world entity\n");
3032         if (e->e->free)
3033                 PF_WARNING("setattachment: can not modify free entity\n");
3034
3035         if (tagentity == NULL)
3036                 tagentity = sv.edicts;
3037
3038         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3039         if (v)
3040                 v->edict = EDICT_TO_PROG(tagentity);
3041
3042         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3043         if (v)
3044                 v->_float = 0;
3045         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3046         {
3047                 modelindex = (int)tagentity->v->modelindex;
3048                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3049                 {
3050                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3051                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3052                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3053                                                 v->_float = i + 1;
3054                         if (v->_float == 0 && model->alias.aliasnum_tags)
3055                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3056                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3057                                                 v->_float = i + 1;
3058                         if (v->_float == 0)
3059                                 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);
3060                 }
3061                 else
3062                         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));
3063         }
3064 }
3065
3066
3067 /////////////////////////////////////////
3068 // DP_QC_FS_SEARCH extension
3069
3070 // qc fs search handling
3071 #define MAX_SEARCHES 128
3072
3073 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3074
3075 void PR_Search_Init(void)
3076 {
3077         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3078 }
3079
3080 void PR_Search_Reset(void)
3081 {
3082         int i;
3083         // reset the fssearch list
3084         for(i = 0; i < MAX_SEARCHES; i++)
3085                 if(pr_fssearchlist[i])
3086                         FS_FreeSearch(pr_fssearchlist[i]);
3087         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3088 }
3089
3090 /*
3091 =========
3092 PF_search_begin
3093
3094 float search_begin(string pattern, float caseinsensitive, float quiet)
3095 =========
3096 */
3097 void PF_search_begin(void)
3098 {
3099         int handle;
3100         char *pattern;
3101         int caseinsens, quiet;
3102
3103         pattern = G_STRING(OFS_PARM0);
3104
3105         PR_CheckEmptyString(pattern);
3106
3107         caseinsens = G_FLOAT(OFS_PARM1);
3108         quiet = G_FLOAT(OFS_PARM2);
3109         
3110         for(handle = 0; handle < MAX_SEARCHES; handle++)
3111                 if(!pr_fssearchlist[handle])
3112                         break;
3113
3114         if(handle >= MAX_SEARCHES)
3115         {
3116                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3117                 G_FLOAT(OFS_RETURN) = -2;
3118                 return;
3119         }
3120
3121         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3122                 G_FLOAT(OFS_RETURN) = -1;
3123         else
3124                 G_FLOAT(OFS_RETURN) = handle;
3125 }
3126
3127 /*
3128 =========
3129 VM_search_end
3130
3131 void    search_end(float handle)
3132 =========
3133 */
3134 void PF_search_end(void)
3135 {
3136         int handle;
3137
3138         handle = G_FLOAT(OFS_PARM0);
3139         
3140         if(handle < 0 || handle >= MAX_SEARCHES)
3141         {
3142                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3143                 return;
3144         }
3145         if(pr_fssearchlist[handle] == NULL)
3146         {
3147                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3148                 return;
3149         }
3150
3151         FS_FreeSearch(pr_fssearchlist[handle]);
3152         pr_fssearchlist[handle] = NULL;
3153 }
3154
3155 /*
3156 =========
3157 VM_search_getsize
3158
3159 float   search_getsize(float handle)
3160 =========
3161 */
3162 void PF_search_getsize(void)
3163 {
3164         int handle;
3165
3166         handle = G_FLOAT(OFS_PARM0);
3167
3168         if(handle < 0 || handle >= MAX_SEARCHES)
3169         {
3170                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3171                 return;
3172         }
3173         if(pr_fssearchlist[handle] == NULL)
3174         {
3175                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3176                 return;
3177         }
3178         
3179         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3180 }
3181
3182 /*
3183 =========
3184 VM_search_getfilename
3185
3186 string  search_getfilename(float handle, float num)
3187 =========
3188 */
3189 void PF_search_getfilename(void)
3190 {
3191         int handle, filenum;
3192         char *tmp;
3193
3194         handle = G_FLOAT(OFS_PARM0);
3195         filenum = G_FLOAT(OFS_PARM1);
3196
3197         if(handle < 0 || handle >= MAX_SEARCHES)
3198         {
3199                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3200                 return;
3201         }
3202         if(pr_fssearchlist[handle] == NULL)
3203         {
3204                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3205                 return;
3206         }
3207         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3208         {
3209                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3210                 return;
3211         }
3212         
3213         tmp = PR_GetTempString();
3214         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3215
3216         G_INT(OFS_RETURN) = PR_SetString(tmp);
3217 }
3218
3219 void PF_cvar_string (void)
3220 {
3221         char *str;
3222         cvar_t *var;
3223         char *tmp;
3224
3225         str = G_STRING(OFS_PARM0);
3226         var = Cvar_FindVar (str);
3227
3228         tmp = PR_GetTempString();
3229         strcpy(tmp, var->string);
3230
3231         G_INT(OFS_RETURN) = PR_SetString(tmp);
3232 }
3233
3234
3235
3236 builtin_t pr_builtin[] =
3237 {
3238 NULL,                                           // #0
3239 PF_makevectors,                         // #1 void(entity e) makevectors
3240 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3241 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3242 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3243 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3244 PF_break,                                       // #6 void() break
3245 PF_random,                                      // #7 float() random
3246 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3247 PF_normalize,                           // #9 vector(vector v) normalize
3248 PF_error,                                       // #10 void(string e) error
3249 PF_objerror,                            // #11 void(string e) objerror
3250 PF_vlen,                                        // #12 float(vector v) vlen
3251 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3252 PF_Spawn,                                       // #14 entity() spawn
3253 PF_Remove,                                      // #15 void(entity e) remove
3254 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3255 PF_checkclient,                         // #17 entity() clientlist
3256 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3257 PF_precache_sound,                      // #19 void(string s) precache_sound
3258 PF_precache_model,                      // #20 void(string s) precache_model
3259 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3260 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3261 PF_bprint,                                      // #23 void(string s) bprint
3262 PF_sprint,                                      // #24 void(entity client, string s) sprint
3263 PF_dprint,                                      // #25 void(string s) dprint
3264 PF_ftos,                                        // #26 void(string s) ftos
3265 PF_vtos,                                        // #27 void(string s) vtos
3266 PF_coredump,                            // #28 void() coredump
3267 PF_traceon,                                     // #29 void() traceon
3268 PF_traceoff,                            // #30 void() traceoff
3269 PF_eprint,                                      // #31 void(entity e) eprint
3270 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3271 NULL,                                           // #33
3272 PF_droptofloor,                         // #34 float() droptofloor
3273 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3274 PF_rint,                                        // #36 float(float v) rint
3275 PF_floor,                                       // #37 float(float v) floor
3276 PF_ceil,                                        // #38 float(float v) ceil
3277 NULL,                                           // #39
3278 PF_checkbottom,                         // #40 float(entity e) checkbottom
3279 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3280 NULL,                                           // #42
3281 PF_fabs,                                        // #43 float(float f) fabs
3282 PF_aim,                                         // #44 vector(entity e, float speed) aim
3283 PF_cvar,                                        // #45 float(string s) cvar
3284 PF_localcmd,                            // #46 void(string s) localcmd
3285 PF_nextent,                                     // #47 entity(entity e) nextent
3286 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3287 PF_changeyaw,                           // #49 void() ChangeYaw
3288 NULL,                                           // #50
3289 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3290 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3291 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3292 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3293 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3294 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3295 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3296 PF_WriteString,                         // #58 void(float to, string s) WriteString
3297 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3298 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3299 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3300 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3301 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3302 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3303 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3304 NULL,                                           // #66
3305 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3306 PF_precache_file,                       // #68 string(string s) precache_file
3307 PF_makestatic,                          // #69 void(entity e) makestatic
3308 PF_changelevel,                         // #70 void(string s) changelevel
3309 NULL,                                           // #71
3310 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3311 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3312 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3313 PF_precache_model,                      // #75 string(string s) precache_model2
3314 PF_precache_sound,                      // #76 string(string s) precache_sound2
3315 PF_precache_file,                       // #77 string(string s) precache_file2
3316 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3317 NULL,                                           // #79
3318 NULL,                                           // #80
3319 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3320 NULL,                                           // #82
3321 NULL,                                           // #83
3322 NULL,                                           // #84
3323 NULL,                                           // #85
3324 NULL,                                           // #86
3325 NULL,                                           // #87
3326 NULL,                                           // #88
3327 NULL,                                           // #89
3328 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3329 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3330 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3331 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3332 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3333 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3334 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3335 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3336 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3337 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3338 NULL,                                           // #100
3339 NULL,                                           // #101
3340 NULL,                                           // #102
3341 NULL,                                           // #103
3342 NULL,                                           // #104
3343 NULL,                                           // #105
3344 NULL,                                           // #106
3345 NULL,                                           // #107
3346 NULL,                                           // #108
3347 NULL,                                           // #109
3348 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3349 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3350 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3351 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3352 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3353 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3354 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3355 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3356 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3357 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3358 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3359 a a a a a a a a                         // #120-199
3360 a a a a a a a a a a                     // #200-299
3361 a a a a a a a a a a                     // #300-399
3362 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3363 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3364 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3365 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3366 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3367 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3368 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3369 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3370 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3371 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3372 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3373 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3374 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3375 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3376 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3377 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3378 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3379 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3380 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3381 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3382 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3383 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3384 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3385 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3386 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3387 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3388 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3389 PF_te_explosion2,                       // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3390 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3391 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3392 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3393 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3394 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3395 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3396 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3397 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3398 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3399 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3400 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3401 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3402 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3403 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3404 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3405 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3406 PF_search_begin,                        // #444
3407 PF_search_end,                          // #445
3408 PF_search_getsize,                      // #446
3409 PF_search_getfilename,          // #447
3410 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3411 NULL,                                           // #449
3412 a a a a a                                       // #450-499 (LordHavoc)
3413 };
3414
3415 builtin_t *pr_builtins = pr_builtin;
3416 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3417
3418 void PR_Cmd_Init(void)
3419 {
3420         pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3421         PR_Files_Init();
3422         PR_Search_Init();
3423 }
3424
3425 void PR_Cmd_Reset(void)
3426 {
3427         Mem_EmptyPool(pr_strings_mempool);
3428         PR_Search_Reset();
3429         PR_Files_CloseAll();
3430 }
3431