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