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