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