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