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