]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
when realtime mode fails now mentions setting vid_bitsperpixel to 32 as well
[divverent/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t  sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24
25 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
26
27
28 /*
29 ===============================================================================
30
31                                                 BUILT-IN FUNCTIONS
32
33 ===============================================================================
34 */
35
36
37 char *PF_VarString (int first)
38 {
39         int             i;
40         static char out[4096]; // FIXME: buffer overflow potential
41
42         out[0] = 0;
43         for (i = first;i < pr_argc;i++)
44                 strcat (out, G_STRING((OFS_PARM0+i*3)));
45         return out;
46 }
47
48 char *ENGINE_EXTENSIONS =
49 "DP_ENT_ALPHA "
50 "DP_ENT_CUSTOMCOLORMAP "
51 "DP_ENT_EXTERIORMODELTOCLIENT "
52 "DP_ENT_LOWPRECISION "
53 "DP_ENT_GLOW "
54 "DP_ENT_SCALE "
55 "DP_ENT_VIEWMODEL "
56 "DP_GFX_FOG "
57 "DP_HALFLIFE_MAP "
58 "DP_INPUTBUTTONS "
59 "DP_MONSTERWALK "
60 "DP_MOVETYPEFOLLOW "
61 "DP_QC_CHANGEPITCH "
62 "DP_QC_COPYENTITY "
63 "DP_QC_ETOS "
64 "DP_QC_FINDCHAIN "
65 "DP_QC_FINDCHAINFLOAT "
66 "DP_QC_FINDFLOAT "
67 "DP_QC_GETLIGHT "
68 "DP_QC_MINMAXBOUND "
69 "DP_QC_RANDOMVEC "
70 "DP_QC_SINCOSSQRTPOW "
71 "DP_QC_TRACEBOX "
72 "DP_QC_TRACETOSS "
73 "DP_QC_VECTORVECTORS "
74 "DP_QUAKE2_MODEL "
75 "DP_REGISTERCVAR "
76 "DP_SOLIDCORPSE "
77 "DP_SPRITE32 "
78 "DP_SV_DRAWONLYTOCLIENT "
79 "DP_SV_EFFECT "
80 "DP_SV_EXTERIORMODELTOCLIENT "
81 "DP_SV_NODRAWTOCLIENT "
82 "DP_SV_PLAYERPHYSICS "
83 "DP_SV_SETCOLOR "
84 "DP_SV_SLOWMO "
85 "DP_TE_BLOOD "
86 "DP_TE_BLOODSHOWER "
87 "DP_TE_EXPLOSIONRGB "
88 "DP_TE_PARTICLECUBE "
89 "DP_TE_PARTICLERAIN "
90 "DP_TE_PARTICLESNOW "
91 "DP_TE_SPARK "
92 "NEH_CMD_PLAY2 "
93 "NEH_RESTOREGAME "
94 "TW_SV_STEPCONTROL "
95 ;
96
97 qboolean checkextension(char *name)
98 {
99         int len;
100         char *e, *start;
101         len = strlen(name);
102         for (e = ENGINE_EXTENSIONS;*e;e++)
103         {
104                 while (*e == ' ')
105                         e++;
106                 if (!*e)
107                         break;
108                 start = e;
109                 while (*e && *e != ' ')
110                         e++;
111                 if (e - start == len)
112                         if (!strncasecmp(start, name, len))
113                                 return true;
114         }
115         return false;
116 }
117
118 /*
119 =================
120 PF_checkextension
121
122 returns true if the extension is supported by the server
123
124 checkextension(extensionname)
125 =================
126 */
127 void PF_checkextension (void)
128 {
129         G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
130 }
131
132 /*
133 =================
134 PF_error
135
136 This is a TERMINAL error, which will kill off the entire server.
137 Dumps self.
138
139 error(value)
140 =================
141 */
142 void PF_error (void)
143 {
144         char    *s;
145         edict_t *ed;
146
147         s = PF_VarString(0);
148         Con_Printf ("======SERVER ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s);
149         ed = PROG_TO_EDICT(pr_global_struct->self);
150         ED_Print (ed);
151
152         Host_Error ("Program error");
153 }
154
155 /*
156 =================
157 PF_objerror
158
159 Dumps out self, then an error message.  The program is aborted and self is
160 removed, but the level can continue.
161
162 objerror(value)
163 =================
164 */
165 void PF_objerror (void)
166 {
167         char    *s;
168         edict_t *ed;
169
170         s = PF_VarString(0);
171         Con_Printf ("======OBJECT ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s);
172         ed = PROG_TO_EDICT(pr_global_struct->self);
173         ED_Print (ed);
174         ED_Free (ed);
175 }
176
177
178 /*
179 ==============
180 PF_makevectors
181
182 Writes new values for v_forward, v_up, and v_right based on angles
183 makevectors(vector)
184 ==============
185 */
186 void PF_makevectors (void)
187 {
188         AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
189 }
190
191 /*
192 ==============
193 PF_vectorvectors
194
195 Writes new values for v_forward, v_up, and v_right based on the given forward vector
196 vectorvectors(vector, vector)
197 ==============
198 */
199 void PF_vectorvectors (void)
200 {
201         VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
202         VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
203 }
204
205 /*
206 =================
207 PF_setorigin
208
209 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.
210
211 setorigin (entity, origin)
212 =================
213 */
214 void PF_setorigin (void)
215 {
216         edict_t *e;
217         float   *org;
218
219         e = G_EDICT(OFS_PARM0);
220         org = G_VECTOR(OFS_PARM1);
221         VectorCopy (org, e->v->origin);
222         SV_LinkEdict (e, false);
223 }
224
225
226 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
227 {
228         int             i;
229         
230         for (i=0 ; i<3 ; i++)
231                 if (min[i] > max[i])
232                         Host_Error ("backwards mins/maxs");
233
234 // set derived values
235         VectorCopy (min, e->v->mins);
236         VectorCopy (max, e->v->maxs);
237         VectorSubtract (max, min, e->v->size);
238
239         SV_LinkEdict (e, false);
240 }
241
242 /*
243 =================
244 PF_setsize
245
246 the size box is rotated by the current angle
247 LordHavoc: no it isn't...
248
249 setsize (entity, minvector, maxvector)
250 =================
251 */
252 void PF_setsize (void)
253 {
254         edict_t *e;
255         float   *min, *max;
256         
257         e = G_EDICT(OFS_PARM0);
258         min = G_VECTOR(OFS_PARM1);
259         max = G_VECTOR(OFS_PARM2);
260         SetMinMaxSize (e, min, max, false);
261 }
262
263
264 /*
265 =================
266 PF_setmodel
267
268 setmodel(entity, model)
269 =================
270 */
271 void PF_setmodel (void)
272 {
273         edict_t *e;
274         char    *m, **check;
275         model_t *mod;
276         int             i;
277
278         e = G_EDICT(OFS_PARM0);
279         m = G_STRING(OFS_PARM1);
280
281 // check to see if model was properly precached
282         for (i=0, check = sv.model_precache ; *check ; i++, check++)
283                 if (!strcmp(*check, m))
284                         break;
285
286         if (!*check)
287                 Host_Error ("no precache: %s\n", m);
288
289
290         e->v->model = m - pr_strings;
291         e->v->modelindex = i;
292
293         mod = sv.models[ (int)e->v->modelindex];
294
295         if (mod)
296                 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
297         else
298                 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
299 }
300
301 /*
302 =================
303 PF_bprint
304
305 broadcast print to everyone on server
306
307 bprint(value)
308 =================
309 */
310 void PF_bprint (void)
311 {
312         char            *s;
313
314         s = PF_VarString(0);
315         SV_BroadcastPrintf ("%s", s);
316 }
317
318 /*
319 =================
320 PF_sprint
321
322 single print to a specific client
323
324 sprint(clientent, value)
325 =================
326 */
327 void PF_sprint (void)
328 {
329         char            *s;
330         client_t        *client;
331         int                     entnum;
332         
333         entnum = G_EDICTNUM(OFS_PARM0);
334         s = PF_VarString(1);
335         
336         if (entnum < 1 || entnum > svs.maxclients)
337         {
338                 Con_Printf ("tried to sprint to a non-client\n");
339                 return;
340         }
341                 
342         client = &svs.clients[entnum-1];
343                 
344         MSG_WriteChar (&client->message,svc_print);
345         MSG_WriteString (&client->message, s );
346 }
347
348
349 /*
350 =================
351 PF_centerprint
352
353 single print to a specific client
354
355 centerprint(clientent, value)
356 =================
357 */
358 void PF_centerprint (void)
359 {
360         char            *s;
361         client_t        *client;
362         int                     entnum;
363         
364         entnum = G_EDICTNUM(OFS_PARM0);
365         s = PF_VarString(1);
366         
367         if (entnum < 1 || entnum > svs.maxclients)
368         {
369                 Con_Printf ("tried to sprint to a non-client\n");
370                 return;
371         }
372                 
373         client = &svs.clients[entnum-1];
374                 
375         MSG_WriteChar (&client->message,svc_centerprint);
376         MSG_WriteString (&client->message, s );
377 }
378
379
380 /*
381 =================
382 PF_normalize
383
384 vector normalize(vector)
385 =================
386 */
387 void PF_normalize (void)
388 {
389         float   *value1;
390         vec3_t  newvalue;
391         float   new;
392         
393         value1 = G_VECTOR(OFS_PARM0);
394
395         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
396         new = sqrt(new);
397         
398         if (new == 0)
399                 newvalue[0] = newvalue[1] = newvalue[2] = 0;
400         else
401         {
402                 new = 1/new;
403                 newvalue[0] = value1[0] * new;
404                 newvalue[1] = value1[1] * new;
405                 newvalue[2] = value1[2] * new;
406         }
407         
408         VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
409 }
410
411 /*
412 =================
413 PF_vlen
414
415 scalar vlen(vector)
416 =================
417 */
418 void PF_vlen (void)
419 {
420         float   *value1;
421         float   new;
422
423         value1 = G_VECTOR(OFS_PARM0);
424
425         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
426         new = sqrt(new);
427         
428         G_FLOAT(OFS_RETURN) = new;
429 }
430
431 /*
432 =================
433 PF_vectoyaw
434
435 float vectoyaw(vector)
436 =================
437 */
438 void PF_vectoyaw (void)
439 {
440         float   *value1;
441         float   yaw;
442         
443         value1 = G_VECTOR(OFS_PARM0);
444
445         if (value1[1] == 0 && value1[0] == 0)
446                 yaw = 0;
447         else
448         {
449                 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
450                 if (yaw < 0)
451                         yaw += 360;
452         }
453
454         G_FLOAT(OFS_RETURN) = yaw;
455 }
456
457
458 /*
459 =================
460 PF_vectoangles
461
462 vector vectoangles(vector)
463 =================
464 */
465 void PF_vectoangles (void)
466 {
467         float   *value1;
468         float   forward;
469         float   yaw, pitch;
470         
471         value1 = G_VECTOR(OFS_PARM0);
472
473         if (value1[1] == 0 && value1[0] == 0)
474         {
475                 yaw = 0;
476                 if (value1[2] > 0)
477                         pitch = 90;
478                 else
479                         pitch = 270;
480         }
481         else
482         {
483                 // LordHavoc: optimized a bit
484                 if (value1[0])
485                 {
486                         yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
487                         if (yaw < 0)
488                                 yaw += 360;
489                 }
490                 else if (value1[1] > 0)
491                         yaw = 90;
492                 else
493                         yaw = 270;
494
495                 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
496                 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
497                 if (pitch < 0)
498                         pitch += 360;
499         }
500
501         G_FLOAT(OFS_RETURN+0) = pitch;
502         G_FLOAT(OFS_RETURN+1) = yaw;
503         G_FLOAT(OFS_RETURN+2) = 0;
504 }
505
506 /*
507 =================
508 PF_Random
509
510 Returns a number from 0<= num < 1
511
512 random()
513 =================
514 */
515 void PF_random (void)
516 {
517         float           num;
518                 
519         num = (rand ()&0x7fff) / ((float)0x7fff);
520         
521         G_FLOAT(OFS_RETURN) = num;
522 }
523
524 /*
525 =================
526 PF_particle
527
528 particle(origin, color, count)
529 =================
530 */
531 void PF_particle (void)
532 {
533         float           *org, *dir;
534         float           color;
535         float           count;
536                         
537         org = G_VECTOR(OFS_PARM0);
538         dir = G_VECTOR(OFS_PARM1);
539         color = G_FLOAT(OFS_PARM2);
540         count = G_FLOAT(OFS_PARM3);
541         SV_StartParticle (org, dir, color, count);
542 }
543
544
545 /*
546 =================
547 PF_ambientsound
548
549 =================
550 */
551 void PF_ambientsound (void)
552 {
553         char            **check;
554         char            *samp;
555         float           *pos;
556         float           vol, attenuation;
557         int                     i, soundnum, large;
558
559         pos = G_VECTOR (OFS_PARM0);                     
560         samp = G_STRING(OFS_PARM1);
561         vol = G_FLOAT(OFS_PARM2);
562         attenuation = G_FLOAT(OFS_PARM3);
563         
564 // check to see if samp was properly precached
565         for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
566                 if (!strcmp(*check,samp))
567                         break;
568
569         if (!*check)
570         {
571                 Con_Printf ("no precache: %s\n", samp);
572                 return;
573         }
574
575         large = false;
576         if (soundnum >= 256)
577                 large = true;
578
579         // add an svc_spawnambient command to the level signon packet
580
581         if (large)
582                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
583         else
584                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
585
586         for (i=0 ; i<3 ; i++)
587                 MSG_WriteDPCoord(&sv.signon, pos[i]);
588
589         if (large)
590                 MSG_WriteShort (&sv.signon, soundnum);
591         else
592                 MSG_WriteByte (&sv.signon, soundnum);
593
594         MSG_WriteByte (&sv.signon, vol*255);
595         MSG_WriteByte (&sv.signon, attenuation*64);
596
597 }
598
599 /*
600 =================
601 PF_sound
602
603 Each entity can have eight independant sound sources, like voice,
604 weapon, feet, etc.
605
606 Channel 0 is an auto-allocate channel, the others override anything
607 already running on that entity/channel pair.
608
609 An attenuation of 0 will play full volume everywhere in the level.
610 Larger attenuations will drop off.
611
612 =================
613 */
614 void PF_sound (void)
615 {
616         char            *sample;
617         int                     channel;
618         edict_t         *entity;
619         int             volume;
620         float attenuation;
621                 
622         entity = G_EDICT(OFS_PARM0);
623         channel = G_FLOAT(OFS_PARM1);
624         sample = G_STRING(OFS_PARM2);
625         volume = G_FLOAT(OFS_PARM3) * 255;
626         attenuation = G_FLOAT(OFS_PARM4);
627         
628         if (volume < 0 || volume > 255)
629                 Host_Error ("SV_StartSound: volume = %i", volume);
630
631         if (attenuation < 0 || attenuation > 4)
632                 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
633
634         if (channel < 0 || channel > 7)
635                 Host_Error ("SV_StartSound: channel = %i", channel);
636
637         SV_StartSound (entity, channel, sample, volume, attenuation);
638 }
639
640 /*
641 =================
642 PF_break
643
644 break()
645 =================
646 */
647 void PF_break (void)
648 {
649         Host_Error ("break statement");
650 }
651
652 /*
653 =================
654 PF_traceline
655
656 Used for use tracing and shot targeting
657 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
658 if the tryents flag is set.
659
660 traceline (vector1, vector2, tryents)
661 =================
662 */
663 void PF_traceline (void)
664 {
665         float   *v1, *v2;
666         trace_t trace;
667         int             nomonsters;
668         edict_t *ent;
669
670         v1 = G_VECTOR(OFS_PARM0);
671         v2 = G_VECTOR(OFS_PARM1);
672         nomonsters = G_FLOAT(OFS_PARM2);
673         ent = G_EDICT(OFS_PARM3);
674
675         trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
676
677         pr_global_struct->trace_allsolid = trace.allsolid;
678         pr_global_struct->trace_startsolid = trace.startsolid;
679         pr_global_struct->trace_fraction = trace.fraction;
680         pr_global_struct->trace_inwater = trace.inwater;
681         pr_global_struct->trace_inopen = trace.inopen;
682         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
683         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
684         pr_global_struct->trace_plane_dist =  trace.plane.dist;
685         if (trace.ent)
686                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
687         else
688                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
689         // FIXME: add trace_endcontents
690 }
691
692
693 /*
694 =================
695 PF_tracebox
696
697 Used for use tracing and shot targeting
698 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
699 if the tryents flag is set.
700
701 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
702 =================
703 */
704 // LordHavoc: added this for my own use, VERY useful, similar to traceline
705 void PF_tracebox (void)
706 {
707         float   *v1, *v2, *m1, *m2;
708         trace_t trace;
709         int             nomonsters;
710         edict_t *ent;
711
712         v1 = G_VECTOR(OFS_PARM0);
713         m1 = G_VECTOR(OFS_PARM1);
714         m2 = G_VECTOR(OFS_PARM2);
715         v2 = G_VECTOR(OFS_PARM3);
716         nomonsters = G_FLOAT(OFS_PARM4);
717         ent = G_EDICT(OFS_PARM5);
718
719         trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
720
721         pr_global_struct->trace_allsolid = trace.allsolid;
722         pr_global_struct->trace_startsolid = trace.startsolid;
723         pr_global_struct->trace_fraction = trace.fraction;
724         pr_global_struct->trace_inwater = trace.inwater;
725         pr_global_struct->trace_inopen = trace.inopen;
726         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
727         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
728         pr_global_struct->trace_plane_dist =  trace.plane.dist; 
729         if (trace.ent)
730                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
731         else
732                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
733 }
734
735 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
736 void PF_TraceToss (void)
737 {
738         trace_t trace;
739         edict_t *ent;
740         edict_t *ignore;
741
742         ent = G_EDICT(OFS_PARM0);
743         ignore = G_EDICT(OFS_PARM1);
744
745         trace = SV_Trace_Toss (ent, ignore);
746
747         pr_global_struct->trace_allsolid = trace.allsolid;
748         pr_global_struct->trace_startsolid = trace.startsolid;
749         pr_global_struct->trace_fraction = trace.fraction;
750         pr_global_struct->trace_inwater = trace.inwater;
751         pr_global_struct->trace_inopen = trace.inopen;
752         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
753         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
754         pr_global_struct->trace_plane_dist =  trace.plane.dist; 
755         if (trace.ent)
756                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
757         else
758                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
759 }
760
761
762 /*
763 =================
764 PF_checkpos
765
766 Returns true if the given entity can move to the given position from it's
767 current position by walking or rolling.
768 FIXME: make work...
769 scalar checkpos (entity, vector)
770 =================
771 */
772 void PF_checkpos (void)
773 {
774 }
775
776 //============================================================================
777
778 qbyte checkpvs[MAX_MAP_LEAFS/8];
779
780 int PF_newcheckclient (int check)
781 {
782         int             i;
783         qbyte   *pvs;
784         edict_t *ent;
785         mleaf_t *leaf;
786         vec3_t  org;
787
788 // cycle to the next one
789
790         if (check < 1)
791                 check = 1;
792         if (check > svs.maxclients)
793                 check = svs.maxclients;
794
795         if (check == svs.maxclients)
796                 i = 1;
797         else
798                 i = check + 1;
799
800         for ( ;  ; i++)
801         {
802                 if (i == svs.maxclients+1)
803                         i = 1;
804
805                 ent = EDICT_NUM(i);
806
807                 if (i == check)
808                         break;  // didn't find anything else
809
810                 if (ent->free)
811                         continue;
812                 if (ent->v->health <= 0)
813                         continue;
814                 if ((int)ent->v->flags & FL_NOTARGET)
815                         continue;
816
817         // anything that is a client, or has a client as an enemy
818                 break;
819         }
820
821 // get the PVS for the entity
822         VectorAdd (ent->v->origin, ent->v->view_ofs, org);
823         leaf = Mod_PointInLeaf (org, sv.worldmodel);
824         pvs = Mod_LeafPVS (leaf, sv.worldmodel);
825         memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
826
827         return i;
828 }
829
830 /*
831 =================
832 PF_checkclient
833
834 Returns a client (or object that has a client enemy) that would be a
835 valid target.
836
837 If there is more than one valid option, they are cycled each frame
838
839 If (self.origin + self.viewofs) is not in the PVS of the current target,
840 it is not returned at all.
841
842 name checkclient ()
843 =================
844 */
845 int c_invis, c_notvis;
846 void PF_checkclient (void)
847 {
848         edict_t *ent, *self;
849         mleaf_t *leaf;
850         int             l;
851         vec3_t  view;
852
853         // find a new check if on a new frame
854         if (sv.time - sv.lastchecktime >= 0.1)
855         {
856                 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
857                 sv.lastchecktime = sv.time;
858         }
859
860         // return check if it might be visible
861         ent = EDICT_NUM(sv.lastcheck);
862         if (ent->free || ent->v->health <= 0)
863         {
864                 RETURN_EDICT(sv.edicts);
865                 return;
866         }
867
868         // if current entity can't possibly see the check entity, return 0
869         self = PROG_TO_EDICT(pr_global_struct->self);
870         VectorAdd (self->v->origin, self->v->view_ofs, view);
871         leaf = Mod_PointInLeaf (view, sv.worldmodel);
872         if (leaf)
873         {
874                 l = (leaf - sv.worldmodel->leafs) - 1;
875                 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
876                 {
877                         c_notvis++;
878                         RETURN_EDICT(sv.edicts);
879                         return;
880                 }
881         }
882
883         // might be able to see it
884         c_invis++;
885         RETURN_EDICT(ent);
886 }
887
888 //============================================================================
889
890
891 /*
892 =================
893 PF_stuffcmd
894
895 Sends text over to the client's execution buffer
896
897 stuffcmd (clientent, value)
898 =================
899 */
900 void PF_stuffcmd (void)
901 {
902         int             entnum;
903         char    *str;
904         client_t        *old;
905         
906         entnum = G_EDICTNUM(OFS_PARM0);
907         if (entnum < 1 || entnum > svs.maxclients)
908                 Host_Error ("Parm 0 not a client");
909         str = G_STRING(OFS_PARM1);      
910
911         old = host_client;
912         host_client = &svs.clients[entnum-1];
913         Host_ClientCommands ("%s", str);
914         host_client = old;
915 }
916
917 /*
918 =================
919 PF_localcmd
920
921 Sends text over to the client's execution buffer
922
923 localcmd (string)
924 =================
925 */
926 void PF_localcmd (void)
927 {
928         char    *str;
929
930         str = G_STRING(OFS_PARM0);      
931         Cbuf_AddText (str);
932 }
933
934 /*
935 =================
936 PF_cvar
937
938 float cvar (string)
939 =================
940 */
941 void PF_cvar (void)
942 {
943         char    *str;
944         
945         str = G_STRING(OFS_PARM0);
946
947         G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
948 }
949
950 /*
951 =================
952 PF_cvar_set
953
954 float cvar (string)
955 =================
956 */
957 void PF_cvar_set (void)
958 {
959         char    *var, *val;
960         
961         var = G_STRING(OFS_PARM0);
962         val = G_STRING(OFS_PARM1);
963         
964         Cvar_Set (var, val);
965 }
966
967 /*
968 =================
969 PF_findradius
970
971 Returns a chain of entities that have origins within a spherical area
972
973 findradius (origin, radius)
974 =================
975 */
976 void PF_findradius (void)
977 {
978         edict_t *ent, *chain;
979         float radius;
980         float radius2;
981         float *org;
982         float eorg[3];
983         int i;
984
985         chain = (edict_t *)sv.edicts;
986
987         org = G_VECTOR(OFS_PARM0);
988         radius = G_FLOAT(OFS_PARM1);
989         radius2 = radius * radius;
990
991         ent = NEXT_EDICT(sv.edicts);
992         for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
993         {
994                 if (ent->free)
995                         continue;
996                 if (ent->v->solid == SOLID_NOT)
997                         continue;
998
999                 // LordHavoc: compare against bounding box rather than center,
1000                 // and use DotProduct instead of Length, major speedup
1001                 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1002                 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1003                 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1004                 if (DotProduct(eorg, eorg) > radius2)
1005                         continue;
1006
1007                 ent->v->chain = EDICT_TO_PROG(chain);
1008                 chain = ent;
1009         }
1010
1011         RETURN_EDICT(chain);
1012 }
1013
1014
1015 /*
1016 =========
1017 PF_dprint
1018 =========
1019 */
1020 void PF_dprint (void)
1021 {
1022         Con_DPrintf ("%s",PF_VarString(0));
1023 }
1024
1025 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1026 #define STRINGTEMP_BUFFERS 16
1027 #define STRINGTEMP_LENGTH 128
1028 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1029 static int pr_string_tempindex = 0;
1030
1031 static char *PR_GetTempString(void)
1032 {
1033         char *s;
1034         s = pr_string_temp[pr_string_tempindex];
1035         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1036         return s;
1037 }
1038
1039 void PF_ftos (void)
1040 {
1041         float v;
1042         char *s;
1043         v = G_FLOAT(OFS_PARM0);
1044
1045         s = PR_GetTempString();
1046         // LordHavoc: ftos improvement
1047         sprintf (s, "%g", v);
1048         G_INT(OFS_RETURN) = s - pr_strings;
1049 }
1050
1051 void PF_fabs (void)
1052 {
1053         float   v;
1054         v = G_FLOAT(OFS_PARM0);
1055         G_FLOAT(OFS_RETURN) = fabs(v);
1056 }
1057
1058 void PF_vtos (void)
1059 {
1060         char *s;
1061         s = PR_GetTempString();
1062         sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1063         G_INT(OFS_RETURN) = s - pr_strings;
1064 }
1065
1066 void PF_etos (void)
1067 {
1068         char *s;
1069         s = PR_GetTempString();
1070         sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1071         G_INT(OFS_RETURN) = s - pr_strings;
1072 }
1073
1074 void PF_Spawn (void)
1075 {
1076         edict_t *ed;
1077         ed = ED_Alloc();
1078         RETURN_EDICT(ed);
1079 }
1080
1081 void PF_Remove (void)
1082 {
1083         edict_t *ed;
1084
1085         ed = G_EDICT(OFS_PARM0);
1086         if (ed == sv.edicts)
1087                 Host_Error("remove: tried to remove world\n");
1088         if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1089                 Host_Error("remove: tried to remove a client\n");
1090         ED_Free (ed);
1091 }
1092
1093
1094 // entity (entity start, .string field, string match) find = #5;
1095 void PF_Find (void)
1096 {
1097         int             e;
1098         int             f;
1099         char    *s, *t;
1100         edict_t *ed;
1101
1102         e = G_EDICTNUM(OFS_PARM0);
1103         f = G_INT(OFS_PARM1);
1104         s = G_STRING(OFS_PARM2);
1105         if (!s || !s[0])
1106         {
1107                 RETURN_EDICT(sv.edicts);
1108                 return;
1109         }
1110
1111         for (e++ ; e < sv.num_edicts ; e++)
1112         {
1113                 ed = EDICT_NUM(e);
1114                 if (ed->free)
1115                         continue;
1116                 t = E_STRING(ed,f);
1117                 if (!t)
1118                         continue;
1119                 if (!strcmp(t,s))
1120                 {
1121                         RETURN_EDICT(ed);
1122                         return;
1123                 }
1124         }
1125
1126         RETURN_EDICT(sv.edicts);
1127 }
1128
1129 // LordHavoc: added this for searching float, int, and entity reference fields
1130 void PF_FindFloat (void)
1131 {
1132         int             e;
1133         int             f;
1134         float   s;
1135         edict_t *ed;
1136
1137         e = G_EDICTNUM(OFS_PARM0);
1138         f = G_INT(OFS_PARM1);
1139         s = G_FLOAT(OFS_PARM2);
1140
1141         for (e++ ; e < sv.num_edicts ; e++)
1142         {
1143                 ed = EDICT_NUM(e);
1144                 if (ed->free)
1145                         continue;
1146                 if (E_FLOAT(ed,f) == s)
1147                 {
1148                         RETURN_EDICT(ed);
1149                         return;
1150                 }
1151         }
1152
1153         RETURN_EDICT(sv.edicts);
1154 }
1155
1156 // chained search for strings in entity fields
1157 // entity(.string field, string match) findchain = #402;
1158 void PF_findchain (void)
1159 {
1160         int             i;
1161         int             f;
1162         char    *s, *t;
1163         edict_t *ent, *chain;
1164
1165         chain = (edict_t *)sv.edicts;
1166
1167         f = G_INT(OFS_PARM0);
1168         s = G_STRING(OFS_PARM1);
1169         if (!s || !s[0])
1170         {
1171                 RETURN_EDICT(sv.edicts);
1172                 return;
1173         }
1174
1175         ent = NEXT_EDICT(sv.edicts);
1176         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1177         {
1178                 if (ent->free)
1179                         continue;
1180                 t = E_STRING(ent,f);
1181                 if (!t)
1182                         continue;
1183                 if (strcmp(t,s))
1184                         continue;
1185
1186                 ent->v->chain = EDICT_TO_PROG(chain);
1187                 chain = ent;
1188         }
1189
1190         RETURN_EDICT(chain);
1191 }
1192
1193 // LordHavoc: chained search for float, int, and entity reference fields
1194 // entity(.string field, float match) findchainfloat = #403;
1195 void PF_findchainfloat (void)
1196 {
1197         int             i;
1198         int             f;
1199         float   s;
1200         edict_t *ent, *chain;
1201
1202         chain = (edict_t *)sv.edicts;
1203
1204         f = G_INT(OFS_PARM0);
1205         s = G_FLOAT(OFS_PARM1);
1206
1207         ent = NEXT_EDICT(sv.edicts);
1208         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1209         {
1210                 if (ent->free)
1211                         continue;
1212                 if (E_FLOAT(ent,f) != s)
1213                         continue;
1214
1215                 ent->v->chain = EDICT_TO_PROG(chain);
1216                 chain = ent;
1217         }
1218
1219         RETURN_EDICT(chain);
1220 }
1221
1222 void PR_CheckEmptyString (char *s)
1223 {
1224         if (s[0] <= ' ')
1225                 Host_Error ("Bad string");
1226 }
1227
1228 void PF_precache_file (void)
1229 {       // precache_file is only used to copy files with qcc, it does nothing
1230         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1231 }
1232
1233 void PF_precache_sound (void)
1234 {
1235         char    *s;
1236         int             i;
1237
1238         if (sv.state != ss_loading)
1239                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1240
1241         s = G_STRING(OFS_PARM0);
1242         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1243         PR_CheckEmptyString (s);
1244
1245         for (i=0 ; i<MAX_SOUNDS ; i++)
1246         {
1247                 if (!sv.sound_precache[i])
1248                 {
1249                         sv.sound_precache[i] = s;
1250                         return;
1251                 }
1252                 if (!strcmp(sv.sound_precache[i], s))
1253                         return;
1254         }
1255         Host_Error ("PF_precache_sound: overflow");
1256 }
1257
1258 void PF_precache_model (void)
1259 {
1260         char    *s;
1261         int             i;
1262
1263         if (sv.state != ss_loading)
1264                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1265
1266         s = G_STRING(OFS_PARM0);
1267         if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1268                 return;
1269         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1270         PR_CheckEmptyString (s);
1271
1272         for (i=0 ; i<MAX_MODELS ; i++)
1273         {
1274                 if (!sv.model_precache[i])
1275                 {
1276                         sv.model_precache[i] = s;
1277                         sv.models[i] = Mod_ForName (s, true, false, false);
1278                         return;
1279                 }
1280                 if (!strcmp(sv.model_precache[i], s))
1281                         return;
1282         }
1283         Host_Error ("PF_precache_model: overflow");
1284 }
1285
1286
1287 void PF_coredump (void)
1288 {
1289         ED_PrintEdicts ();
1290 }
1291
1292 void PF_traceon (void)
1293 {
1294         pr_trace = true;
1295 }
1296
1297 void PF_traceoff (void)
1298 {
1299         pr_trace = false;
1300 }
1301
1302 void PF_eprint (void)
1303 {
1304         ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1305 }
1306
1307 /*
1308 ===============
1309 PF_walkmove
1310
1311 float(float yaw, float dist) walkmove
1312 ===============
1313 */
1314 void PF_walkmove (void)
1315 {
1316         edict_t *ent;
1317         float   yaw, dist;
1318         vec3_t  move;
1319         dfunction_t     *oldf;
1320         int     oldself;
1321
1322         ent = PROG_TO_EDICT(pr_global_struct->self);
1323         yaw = G_FLOAT(OFS_PARM0);
1324         dist = G_FLOAT(OFS_PARM1);
1325
1326         if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1327         {
1328                 G_FLOAT(OFS_RETURN) = 0;
1329                 return;
1330         }
1331
1332         yaw = yaw*M_PI*2 / 360;
1333
1334         move[0] = cos(yaw)*dist;
1335         move[1] = sin(yaw)*dist;
1336         move[2] = 0;
1337
1338 // save program state, because SV_movestep may call other progs
1339         oldf = pr_xfunction;
1340         oldself = pr_global_struct->self;
1341
1342         G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1343
1344
1345 // restore program state
1346         pr_xfunction = oldf;
1347         pr_global_struct->self = oldself;
1348 }
1349
1350 /*
1351 ===============
1352 PF_droptofloor
1353
1354 void() droptofloor
1355 ===============
1356 */
1357 void PF_droptofloor (void)
1358 {
1359         edict_t         *ent;
1360         vec3_t          end;
1361         trace_t         trace;
1362
1363         ent = PROG_TO_EDICT(pr_global_struct->self);
1364
1365         VectorCopy (ent->v->origin, end);
1366         end[2] -= 256;
1367
1368         trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1369
1370         if (trace.fraction == 1 || trace.allsolid)
1371                 G_FLOAT(OFS_RETURN) = 0;
1372         else
1373         {
1374                 VectorCopy (trace.endpos, ent->v->origin);
1375                 SV_LinkEdict (ent, false);
1376                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1377                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1378                 G_FLOAT(OFS_RETURN) = 1;
1379                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1380                 ent->suspendedinairflag = true;
1381         }
1382 }
1383
1384 /*
1385 ===============
1386 PF_lightstyle
1387
1388 void(float style, string value) lightstyle
1389 ===============
1390 */
1391 void PF_lightstyle (void)
1392 {
1393         int             style;
1394         char    *val;
1395         client_t        *client;
1396         int                     j;
1397
1398         style = G_FLOAT(OFS_PARM0);
1399         val = G_STRING(OFS_PARM1);
1400
1401 // change the string in sv
1402         sv.lightstyles[style] = val;
1403
1404 // send message to all clients on this server
1405         if (sv.state != ss_active)
1406                 return;
1407
1408         for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1409                 if (client->active || client->spawned)
1410                 {
1411                         MSG_WriteChar (&client->message, svc_lightstyle);
1412                         MSG_WriteChar (&client->message,style);
1413                         MSG_WriteString (&client->message, val);
1414                 }
1415 }
1416
1417 void PF_rint (void)
1418 {
1419         float   f;
1420         f = G_FLOAT(OFS_PARM0);
1421         if (f > 0)
1422                 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1423         else
1424                 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1425 }
1426 void PF_floor (void)
1427 {
1428         G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1429 }
1430 void PF_ceil (void)
1431 {
1432         G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1433 }
1434
1435
1436 /*
1437 =============
1438 PF_checkbottom
1439 =============
1440 */
1441 void PF_checkbottom (void)
1442 {
1443         G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1444 }
1445
1446 /*
1447 =============
1448 PF_pointcontents
1449 =============
1450 */
1451 void PF_pointcontents (void)
1452 {
1453         G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1454 }
1455
1456 /*
1457 =============
1458 PF_nextent
1459
1460 entity nextent(entity)
1461 =============
1462 */
1463 void PF_nextent (void)
1464 {
1465         int             i;
1466         edict_t *ent;
1467
1468         i = G_EDICTNUM(OFS_PARM0);
1469         while (1)
1470         {
1471                 i++;
1472                 if (i == sv.num_edicts)
1473                 {
1474                         RETURN_EDICT(sv.edicts);
1475                         return;
1476                 }
1477                 ent = EDICT_NUM(i);
1478                 if (!ent->free)
1479                 {
1480                         RETURN_EDICT(ent);
1481                         return;
1482                 }
1483         }
1484 }
1485
1486 /*
1487 =============
1488 PF_aim
1489
1490 Pick a vector for the player to shoot along
1491 vector aim(entity, missilespeed)
1492 =============
1493 */
1494 void PF_aim (void)
1495 {
1496         edict_t *ent, *check, *bestent;
1497         vec3_t  start, dir, end, bestdir;
1498         int             i, j;
1499         trace_t tr;
1500         float   dist, bestdist;
1501         float   speed;
1502
1503         ent = G_EDICT(OFS_PARM0);
1504         speed = G_FLOAT(OFS_PARM1);
1505
1506         VectorCopy (ent->v->origin, start);
1507         start[2] += 20;
1508
1509 // try sending a trace straight
1510         VectorCopy (pr_global_struct->v_forward, dir);
1511         VectorMA (start, 2048, dir, end);
1512         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1513         if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1514         && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1515         {
1516                 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1517                 return;
1518         }
1519
1520
1521 // try all possible entities
1522         VectorCopy (dir, bestdir);
1523         bestdist = sv_aim.value;
1524         bestent = NULL;
1525
1526         check = NEXT_EDICT(sv.edicts);
1527         for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1528         {
1529                 if (check->v->takedamage != DAMAGE_AIM)
1530                         continue;
1531                 if (check == ent)
1532                         continue;
1533                 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1534                         continue;       // don't aim at teammate
1535                 for (j=0 ; j<3 ; j++)
1536                         end[j] = check->v->origin[j]
1537                         + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1538                 VectorSubtract (end, start, dir);
1539                 VectorNormalize (dir);
1540                 dist = DotProduct (dir, pr_global_struct->v_forward);
1541                 if (dist < bestdist)
1542                         continue;       // to far to turn
1543                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1544                 if (tr.ent == check)
1545                 {       // can shoot at this one
1546                         bestdist = dist;
1547                         bestent = check;
1548                 }
1549         }
1550
1551         if (bestent)
1552         {
1553                 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1554                 dist = DotProduct (dir, pr_global_struct->v_forward);
1555                 VectorScale (pr_global_struct->v_forward, dist, end);
1556                 end[2] = dir[2];
1557                 VectorNormalize (end);
1558                 VectorCopy (end, G_VECTOR(OFS_RETURN));
1559         }
1560         else
1561         {
1562                 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1563         }
1564 }
1565
1566 /*
1567 ==============
1568 PF_changeyaw
1569
1570 This was a major timewaster in progs, so it was converted to C
1571 ==============
1572 */
1573 void PF_changeyaw (void)
1574 {
1575         edict_t         *ent;
1576         float           ideal, current, move, speed;
1577
1578         ent = PROG_TO_EDICT(pr_global_struct->self);
1579         current = ANGLEMOD(ent->v->angles[1]);
1580         ideal = ent->v->ideal_yaw;
1581         speed = ent->v->yaw_speed;
1582
1583         if (current == ideal)
1584                 return;
1585         move = ideal - current;
1586         if (ideal > current)
1587         {
1588                 if (move >= 180)
1589                         move = move - 360;
1590         }
1591         else
1592         {
1593                 if (move <= -180)
1594                         move = move + 360;
1595         }
1596         if (move > 0)
1597         {
1598                 if (move > speed)
1599                         move = speed;
1600         }
1601         else
1602         {
1603                 if (move < -speed)
1604                         move = -speed;
1605         }
1606
1607         ent->v->angles[1] = ANGLEMOD (current + move);
1608 }
1609
1610 /*
1611 ==============
1612 PF_changepitch
1613 ==============
1614 */
1615 void PF_changepitch (void)
1616 {
1617         edict_t         *ent;
1618         float           ideal, current, move, speed;
1619         eval_t          *val;
1620
1621         ent = G_EDICT(OFS_PARM0);
1622         current = ANGLEMOD( ent->v->angles[0] );
1623         if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1624                 ideal = val->_float;
1625         else
1626         {
1627                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1628                 return;
1629         }
1630         if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1631                 speed = val->_float;
1632         else
1633         {
1634                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1635                 return;
1636         }
1637
1638         if (current == ideal)
1639                 return;
1640         move = ideal - current;
1641         if (ideal > current)
1642         {
1643                 if (move >= 180)
1644                         move = move - 360;
1645         }
1646         else
1647         {
1648                 if (move <= -180)
1649                         move = move + 360;
1650         }
1651         if (move > 0)
1652         {
1653                 if (move > speed)
1654                         move = speed;
1655         }
1656         else
1657         {
1658                 if (move < -speed)
1659                         move = -speed;
1660         }
1661
1662         ent->v->angles[0] = ANGLEMOD (current + move);
1663 }
1664
1665 /*
1666 ===============================================================================
1667
1668 MESSAGE WRITING
1669
1670 ===============================================================================
1671 */
1672
1673 #define MSG_BROADCAST   0               // unreliable to all
1674 #define MSG_ONE                 1               // reliable to one (msg_entity)
1675 #define MSG_ALL                 2               // reliable to all
1676 #define MSG_INIT                3               // write to the init string
1677
1678 sizebuf_t *WriteDest (void)
1679 {
1680         int             entnum;
1681         int             dest;
1682         edict_t *ent;
1683
1684         dest = G_FLOAT(OFS_PARM0);
1685         switch (dest)
1686         {
1687         case MSG_BROADCAST:
1688                 return &sv.datagram;
1689
1690         case MSG_ONE:
1691                 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1692                 entnum = NUM_FOR_EDICT(ent);
1693                 if (entnum < 1 || entnum > svs.maxclients)
1694                         Host_Error ("WriteDest: not a client");
1695                 return &svs.clients[entnum-1].message;
1696
1697         case MSG_ALL:
1698                 return &sv.reliable_datagram;
1699
1700         case MSG_INIT:
1701                 return &sv.signon;
1702
1703         default:
1704                 Host_Error ("WriteDest: bad destination");
1705                 break;
1706         }
1707
1708         return NULL;
1709 }
1710
1711 void PF_WriteByte (void)
1712 {
1713         MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1714 }
1715
1716 void PF_WriteChar (void)
1717 {
1718         MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1719 }
1720
1721 void PF_WriteShort (void)
1722 {
1723         MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1724 }
1725
1726 void PF_WriteLong (void)
1727 {
1728         MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1729 }
1730
1731 void PF_WriteAngle (void)
1732 {
1733         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1734 }
1735
1736 void PF_WriteCoord (void)
1737 {
1738         MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1739 }
1740
1741 void PF_WriteString (void)
1742 {
1743         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1744 }
1745
1746
1747 void PF_WriteEntity (void)
1748 {
1749         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1750 }
1751
1752 //=============================================================================
1753
1754 void PF_makestatic (void)
1755 {
1756         edict_t *ent;
1757         int i, large;
1758
1759         ent = G_EDICT(OFS_PARM0);
1760
1761         large = false;
1762         if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1763                 large = true;
1764
1765         if (large)
1766         {
1767                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1768                 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1769                 MSG_WriteShort (&sv.signon, ent->v->frame);
1770         }
1771         else
1772         {
1773                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1774                 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1775                 MSG_WriteByte (&sv.signon, ent->v->frame);
1776         }
1777
1778         MSG_WriteByte (&sv.signon, ent->v->colormap);
1779         MSG_WriteByte (&sv.signon, ent->v->skin);
1780         for (i=0 ; i<3 ; i++)
1781         {
1782                 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1783                 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1784         }
1785
1786 // throw the entity away now
1787         ED_Free (ent);
1788 }
1789
1790 //=============================================================================
1791
1792 /*
1793 ==============
1794 PF_setspawnparms
1795 ==============
1796 */
1797 void PF_setspawnparms (void)
1798 {
1799         edict_t *ent;
1800         int             i;
1801         client_t        *client;
1802
1803         ent = G_EDICT(OFS_PARM0);
1804         i = NUM_FOR_EDICT(ent);
1805         if (i < 1 || i > svs.maxclients)
1806                 Host_Error ("Entity is not a client");
1807
1808         // copy spawn parms out of the client_t
1809         client = svs.clients + (i-1);
1810
1811         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1812                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1813 }
1814
1815 /*
1816 ==============
1817 PF_changelevel
1818 ==============
1819 */
1820 void PF_changelevel (void)
1821 {
1822         char    *s;
1823
1824 // make sure we don't issue two changelevels
1825         if (svs.changelevel_issued)
1826                 return;
1827         svs.changelevel_issued = true;
1828
1829         s = G_STRING(OFS_PARM0);
1830         Cbuf_AddText (va("changelevel %s\n",s));
1831 }
1832
1833 void PF_sin (void)
1834 {
1835         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1836 }
1837
1838 void PF_cos (void)
1839 {
1840         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1841 }
1842
1843 void PF_sqrt (void)
1844 {
1845         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1846 }
1847
1848 /*
1849 =================
1850 PF_RandomVec
1851
1852 Returns a vector of length < 1
1853
1854 randomvec()
1855 =================
1856 */
1857 void PF_randomvec (void)
1858 {
1859         vec3_t          temp;
1860         do
1861         {
1862                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1863                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1864                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1865         }
1866         while (DotProduct(temp, temp) >= 1);
1867         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1868 }
1869
1870 void SV_LightPoint (vec3_t color, vec3_t p);
1871 /*
1872 =================
1873 PF_GetLight
1874
1875 Returns a color vector indicating the lighting at the requested point.
1876
1877 (Internal Operation note: actually measures the light beneath the point, just like
1878                           the model lighting on the client)
1879
1880 getlight(vector)
1881 =================
1882 */
1883 void PF_GetLight (void)
1884 {
1885         vec3_t          color;
1886         vec_t*          p;
1887         p = G_VECTOR(OFS_PARM0);
1888         SV_LightPoint (color, p);
1889         VectorCopy (color, G_VECTOR(OFS_RETURN));
1890 }
1891
1892 #define MAX_QC_CVARS 128
1893 cvar_t qc_cvar[MAX_QC_CVARS];
1894 int currentqc_cvar;
1895
1896 void PF_registercvar (void)
1897 {
1898         char *name, *value;
1899         cvar_t *variable;
1900         name = G_STRING(OFS_PARM0);
1901         value = G_STRING(OFS_PARM1);
1902         G_FLOAT(OFS_RETURN) = 0;
1903 // first check to see if it has already been defined
1904         if (Cvar_FindVar (name))
1905                 return;
1906
1907 // check for overlap with a command
1908         if (Cmd_Exists (name))
1909         {
1910                 Con_Printf ("PF_registercvar: %s is a command\n", name);
1911                 return;
1912         }
1913
1914         if (currentqc_cvar >= MAX_QC_CVARS)
1915                 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1916
1917 // copy the name and value
1918         variable = &qc_cvar[currentqc_cvar++];
1919         variable->name = Z_Malloc (strlen(name)+1);
1920         strcpy (variable->name, name);
1921         variable->string = Z_Malloc (strlen(value)+1);
1922         strcpy (variable->string, value);
1923         variable->value = atof (value);
1924
1925         Cvar_RegisterVariable(variable);
1926         G_FLOAT(OFS_RETURN) = 1; // success
1927 }
1928
1929 /*
1930 =================
1931 PF_min
1932
1933 returns the minimum of two supplied floats
1934
1935 min(a, b)
1936 =================
1937 */
1938 void PF_min (void)
1939 {
1940         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1941         if (pr_argc == 2)
1942                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1943         else if (pr_argc >= 3)
1944         {
1945                 int i;
1946                 float f = G_FLOAT(OFS_PARM0);
1947                 for (i = 1;i < pr_argc;i++)
1948                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
1949                                 f = G_FLOAT((OFS_PARM0+i*3));
1950                 G_FLOAT(OFS_RETURN) = f;
1951         }
1952         else
1953                 Host_Error("min: must supply at least 2 floats\n");
1954 }
1955
1956 /*
1957 =================
1958 PF_max
1959
1960 returns the maximum of two supplied floats
1961
1962 max(a, b)
1963 =================
1964 */
1965 void PF_max (void)
1966 {
1967         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1968         if (pr_argc == 2)
1969                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1970         else if (pr_argc >= 3)
1971         {
1972                 int i;
1973                 float f = G_FLOAT(OFS_PARM0);
1974                 for (i = 1;i < pr_argc;i++)
1975                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
1976                                 f = G_FLOAT((OFS_PARM0+i*3));
1977                 G_FLOAT(OFS_RETURN) = f;
1978         }
1979         else
1980                 Host_Error("max: must supply at least 2 floats\n");
1981 }
1982
1983 /*
1984 =================
1985 PF_bound
1986
1987 returns number bounded by supplied range
1988
1989 min(min, value, max)
1990 =================
1991 */
1992 void PF_bound (void)
1993 {
1994         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
1995 }
1996
1997 /*
1998 =================
1999 PF_pow
2000
2001 returns a raised to power b
2002
2003 pow(a, b)
2004 =================
2005 */
2006 void PF_pow (void)
2007 {
2008         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2009 }
2010
2011 /*
2012 =================
2013 PF_copyentity
2014
2015 copies data from one entity to another
2016
2017 copyentity(src, dst)
2018 =================
2019 */
2020 void PF_copyentity (void)
2021 {
2022         edict_t *in, *out;
2023         in = G_EDICT(OFS_PARM0);
2024         out = G_EDICT(OFS_PARM1);
2025         memcpy(out->v, in->v, progs->entityfields * 4);
2026 }
2027
2028 /*
2029 =================
2030 PF_setcolor
2031
2032 sets the color of a client and broadcasts the update to all connected clients
2033
2034 setcolor(clientent, value)
2035 =================
2036 */
2037 void PF_setcolor (void)
2038 {
2039         client_t        *client;
2040         int                     entnum, i;
2041
2042         entnum = G_EDICTNUM(OFS_PARM0);
2043         i = G_FLOAT(OFS_PARM1);
2044
2045         if (entnum < 1 || entnum > svs.maxclients)
2046         {
2047                 Con_Printf ("tried to setcolor a non-client\n");
2048                 return;
2049         }
2050
2051         client = &svs.clients[entnum-1];
2052         client->colors = i;
2053         client->edict->v->team = (i & 15) + 1;
2054
2055         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2056         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2057         MSG_WriteByte (&sv.reliable_datagram, i);
2058 }
2059
2060 /*
2061 =================
2062 PF_effect
2063
2064 effect(origin, modelname, startframe, framecount, framerate)
2065 =================
2066 */
2067 void PF_effect (void)
2068 {
2069         char *s;
2070         s = G_STRING(OFS_PARM1);
2071         if (!s || !s[0])
2072                 Host_Error("effect: no model specified\n");
2073
2074         SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2075 }
2076
2077 void PF_te_blood (void)
2078 {
2079         if (G_FLOAT(OFS_PARM2) < 1)
2080                 return;
2081         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2082         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2083         // origin
2084         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2085         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2086         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2087         // velocity
2088         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2089         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2090         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2091         // count
2092         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2093 }
2094
2095 void PF_te_bloodshower (void)
2096 {
2097         if (G_FLOAT(OFS_PARM3) < 1)
2098                 return;
2099         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2100         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2101         // min
2102         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2103         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2104         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2105         // max
2106         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2107         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2108         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2109         // speed
2110         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2111         // count
2112         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2113 }
2114
2115 void PF_te_explosionrgb (void)
2116 {
2117         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2118         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2119         // origin
2120         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2121         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2122         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2123         // color
2124         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2125         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2126         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2127 }
2128
2129 void PF_te_particlecube (void)
2130 {
2131         if (G_FLOAT(OFS_PARM3) < 1)
2132                 return;
2133         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2134         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2135         // min
2136         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2137         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2138         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2139         // max
2140         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2141         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2142         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2143         // velocity
2144         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2145         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2146         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2147         // count
2148         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2149         // color
2150         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2151         // gravity true/false
2152         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2153         // randomvel
2154         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2155 }
2156
2157 void PF_te_particlerain (void)
2158 {
2159         if (G_FLOAT(OFS_PARM3) < 1)
2160                 return;
2161         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2162         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2163         // min
2164         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2165         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2166         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2167         // max
2168         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2169         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2170         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2171         // velocity
2172         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2173         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2174         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2175         // count
2176         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2177         // color
2178         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2179 }
2180
2181 void PF_te_particlesnow (void)
2182 {
2183         if (G_FLOAT(OFS_PARM3) < 1)
2184                 return;
2185         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2186         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2187         // min
2188         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2189         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2190         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2191         // max
2192         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2193         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2194         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2195         // velocity
2196         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2197         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2198         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2199         // count
2200         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2201         // color
2202         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2203 }
2204
2205 void PF_te_spark (void)
2206 {
2207         if (G_FLOAT(OFS_PARM2) < 1)
2208                 return;
2209         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2210         MSG_WriteByte(&sv.datagram, TE_SPARK);
2211         // origin
2212         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2213         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2214         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2215         // velocity
2216         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2217         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2218         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2219         // count
2220         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2221 }
2222
2223 void PF_te_gunshotquad (void)
2224 {
2225         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2226         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2227         // origin
2228         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2229         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2230         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2231 }
2232
2233 void PF_te_spikequad (void)
2234 {
2235         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2236         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2237         // origin
2238         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2239         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2240         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2241 }
2242
2243 void PF_te_superspikequad (void)
2244 {
2245         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2246         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2247         // origin
2248         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2249         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2250         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2251 }
2252
2253 void PF_te_explosionquad (void)
2254 {
2255         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2256         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2257         // origin
2258         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2259         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2260         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2261 }
2262
2263 void PF_te_smallflash (void)
2264 {
2265         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2266         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2267         // origin
2268         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2269         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2270         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2271 }
2272
2273 void PF_te_customflash (void)
2274 {
2275         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2276                 return;
2277         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2279         // origin
2280         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2281         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2282         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2283         // radius
2284         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2285         // lifetime
2286         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2287         // color
2288         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2289         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2290         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2291 }
2292
2293 void PF_te_gunshot (void)
2294 {
2295         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2296         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2297         // origin
2298         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2299         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2300         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2301 }
2302
2303 void PF_te_spike (void)
2304 {
2305         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2306         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2307         // origin
2308         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2309         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2310         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2311 }
2312
2313 void PF_te_superspike (void)
2314 {
2315         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2316         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2317         // origin
2318         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2319         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2320         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2321 }
2322
2323 void PF_te_explosion (void)
2324 {
2325         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2326         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2327         // origin
2328         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2329         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2330         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2331 }
2332
2333 void PF_te_tarexplosion (void)
2334 {
2335         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2336         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2337         // origin
2338         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2339         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2340         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2341 }
2342
2343 void PF_te_wizspike (void)
2344 {
2345         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2346         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2347         // origin
2348         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2349         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2350         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2351 }
2352
2353 void PF_te_knightspike (void)
2354 {
2355         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2356         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2357         // origin
2358         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2359         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2360         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2361 }
2362
2363 void PF_te_lavasplash (void)
2364 {
2365         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2366         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2367         // origin
2368         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2369         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2370         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2371 }
2372
2373 void PF_te_teleport (void)
2374 {
2375         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2376         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2377         // origin
2378         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2379         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2380         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2381 }
2382
2383 void PF_te_explosion2 (void)
2384 {
2385         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2386         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2387         // origin
2388         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2389         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2390         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2391         // color
2392         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2393 }
2394
2395 void PF_te_lightning1 (void)
2396 {
2397         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2398         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2399         // owner entity
2400         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2401         // start
2402         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2403         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2404         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2405         // end
2406         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2407         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2408         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2409 }
2410
2411 void PF_te_lightning2 (void)
2412 {
2413         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2414         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2415         // owner entity
2416         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2417         // start
2418         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2419         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2420         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2421         // end
2422         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2423         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2424         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2425 }
2426
2427 void PF_te_lightning3 (void)
2428 {
2429         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2430         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2431         // owner entity
2432         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2433         // start
2434         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2435         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2436         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2437         // end
2438         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2439         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2440         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2441 }
2442
2443 void PF_te_beam (void)
2444 {
2445         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2446         MSG_WriteByte(&sv.datagram, TE_BEAM);
2447         // owner entity
2448         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2449         // start
2450         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2451         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2452         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2453         // end
2454         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2455         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2456         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2457 }
2458
2459 void PF_te_plasmaburn (void)
2460 {
2461         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2462         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
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 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2469 {
2470         int i, j;
2471         vec3_t v1, clipplanenormal, normal;
2472         vec_t clipplanedist, clipdist;
2473         VectorCopy(p, out);
2474         if (surf->flags & SURF_PLANEBACK)
2475                 VectorNegate(surf->plane->normal, normal);
2476         else
2477                 VectorCopy(surf->plane->normal, normal);
2478         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2479         {
2480                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2481                 VectorNormalizeFast(v1);
2482                 CrossProduct(v1, normal, clipplanenormal);
2483                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2484                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2485                 if (clipdist > 0)
2486                 {
2487                         clipdist = -clipdist;
2488                         VectorMA(out, clipdist, clipplanenormal, out);
2489                 }
2490         }
2491 }
2492
2493 static msurface_t *getsurface(edict_t *ed, int surfnum)
2494 {
2495         int modelindex;
2496         model_t *model;
2497         if (!ed || ed->free)
2498                 return NULL;
2499         modelindex = ed->v->modelindex;
2500         if (modelindex < 1 || modelindex >= MAX_MODELS)
2501                 return NULL;
2502         model = sv.models[modelindex];
2503         if (model->type != mod_brush)
2504                 return NULL;
2505         if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2506                 return NULL;
2507         return model->surfaces + surfnum + model->firstmodelsurface;
2508 }
2509
2510
2511 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2512 void PF_getsurfacenumpoints(void)
2513 {
2514         msurface_t *surf;
2515         // return 0 if no such surface
2516         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2517         {
2518                 G_FLOAT(OFS_RETURN) = 0;
2519                 return;
2520         }
2521
2522         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2523 }
2524 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2525 void PF_getsurfacepoint(void)
2526 {
2527         edict_t *ed;
2528         msurface_t *surf;
2529         int pointnum;
2530         VectorClear(G_VECTOR(OFS_RETURN));
2531         ed = G_EDICT(OFS_PARM0);
2532         if (!ed || ed->free)
2533                 return;
2534         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2535                 return;
2536         pointnum = G_FLOAT(OFS_PARM2);
2537         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2538                 return;
2539         // FIXME: implement rotation/scaling
2540         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2541 }
2542 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2543 void PF_getsurfacenormal(void)
2544 {
2545         msurface_t *surf;
2546         VectorClear(G_VECTOR(OFS_RETURN));
2547         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2548                 return;
2549         // FIXME: implement rotation/scaling
2550         if (surf->flags & SURF_PLANEBACK)
2551                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2552         else
2553                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2554 }
2555 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2556 void PF_getsurfacetexture(void)
2557 {
2558         msurface_t *surf;
2559         G_INT(OFS_RETURN) = 0;
2560         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2561                 return;
2562         G_INT(OFS_RETURN) = surf->texinfo->texture->name - pr_strings;
2563 }
2564 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2565 void PF_getsurfacenearpoint(void)
2566 {
2567         int surfnum, best, modelindex;
2568         vec3_t clipped, p;
2569         vec_t dist, bestdist;
2570         edict_t *ed;
2571         model_t *model;
2572         msurface_t *surf;
2573         vec_t *point;
2574         G_FLOAT(OFS_RETURN) = -1;
2575         ed = G_EDICT(OFS_PARM0);
2576         point = G_VECTOR(OFS_PARM1);
2577
2578         if (!ed || ed->free)
2579                 return;
2580         modelindex = ed->v->modelindex;
2581         if (modelindex < 1 || modelindex >= MAX_MODELS)
2582                 return;
2583         model = sv.models[modelindex];
2584         if (model->type != mod_brush)
2585                 return;
2586
2587         // FIXME: implement rotation/scaling
2588         VectorSubtract(point, ed->v->origin, p);
2589         best = -1;
2590         bestdist = 1000000000;
2591         for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2592         {
2593                 surf = model->surfaces + surfnum + model->firstmodelsurface;
2594                 dist = PlaneDiff(p, surf->plane);
2595                 dist = dist * dist;
2596                 if (dist < bestdist)
2597                 {
2598                         clippointtosurface(surf, p, clipped);
2599                         VectorSubtract(clipped, p, clipped);
2600                         dist += DotProduct(clipped, clipped);
2601                         if (dist < bestdist)
2602                         {
2603                                 best = surfnum;
2604                                 bestdist = dist;
2605                         }
2606                 }
2607         }
2608         G_FLOAT(OFS_RETURN) = best;
2609 }
2610 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2611 void PF_getsurfaceclippedpoint(void)
2612 {
2613         edict_t *ed;
2614         msurface_t *surf;
2615         vec3_t p, out;
2616         VectorClear(G_VECTOR(OFS_RETURN));
2617         ed = G_EDICT(OFS_PARM0);
2618         if (!ed || ed->free)
2619                 return;
2620         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2621                 return;
2622         // FIXME: implement rotation/scaling
2623         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2624         clippointtosurface(surf, p, out);
2625         // FIXME: implement rotation/scaling
2626         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2627 }
2628
2629 void PF_Fixme (void)
2630 {
2631         Host_Error ("unimplemented QC builtin"); // LordHavoc: was misspelled (bulitin)
2632 }
2633
2634
2635
2636 builtin_t pr_builtin[] =
2637 {
2638 PF_Fixme,
2639 PF_makevectors, // void(entity e)       makevectors             = #1;
2640 PF_setorigin,   // void(entity e, vector o) setorigin   = #2;
2641 PF_setmodel,    // void(entity e, string m) setmodel    = #3;
2642 PF_setsize,     // void(entity e, vector min, vector max) setsize = #4;
2643 PF_Fixme,       // void(entity e, vector min, vector max) setabssize = #5;
2644 PF_break,       // void() break                                         = #6;
2645 PF_random,      // float() random                                               = #7;
2646 PF_sound,       // void(entity e, float chan, string samp) sound = #8;
2647 PF_normalize,   // vector(vector v) normalize                   = #9;
2648 PF_error,       // void(string e) error                         = #10;
2649 PF_objerror,    // void(string e) objerror                              = #11;
2650 PF_vlen,        // float(vector v) vlen                         = #12;
2651 PF_vectoyaw,    // float(vector v) vectoyaw             = #13;
2652 PF_Spawn,       // entity() spawn                                               = #14;
2653 PF_Remove,      // void(entity e) remove                                = #15;
2654 PF_traceline,   // float(vector v1, vector v2, float tryents) traceline = #16;
2655 PF_checkclient, // entity() clientlist                                  = #17;
2656 PF_Find,        // entity(entity start, .string fld, string match) find = #18;
2657 PF_precache_sound,      // void(string s) precache_sound                = #19;
2658 PF_precache_model,      // void(string s) precache_model                = #20;
2659 PF_stuffcmd,    // void(entity client, string s)stuffcmd = #21;
2660 PF_findradius,  // entity(vector org, float rad) findradius = #22;
2661 PF_bprint,      // void(string s) bprint                                = #23;
2662 PF_sprint,      // void(entity client, string s) sprint = #24;
2663 PF_dprint,      // void(string s) dprint                                = #25;
2664 PF_ftos,        // void(string s) ftos                          = #26;
2665 PF_vtos,        // void(string s) vtos                          = #27;
2666 PF_coredump,
2667 PF_traceon,
2668 PF_traceoff,
2669 PF_eprint,      // void(entity e) debug print an entire entity
2670 PF_walkmove, // float(float yaw, float dist) walkmove
2671 PF_Fixme, // float(float yaw, float dist) walkmove
2672 PF_droptofloor,
2673 PF_lightstyle,
2674 PF_rint,
2675 PF_floor,
2676 PF_ceil,
2677 PF_Fixme,
2678 PF_checkbottom,
2679 PF_pointcontents,
2680 PF_Fixme,
2681 PF_fabs,
2682 PF_aim,
2683 PF_cvar,
2684 PF_localcmd,
2685 PF_nextent,
2686 PF_particle,
2687 PF_changeyaw,
2688 PF_Fixme,
2689 PF_vectoangles,
2690
2691 PF_WriteByte,
2692 PF_WriteChar,
2693 PF_WriteShort,
2694 PF_WriteLong,
2695 PF_WriteCoord,
2696 PF_WriteAngle,
2697 PF_WriteString,
2698 PF_WriteEntity,
2699
2700 PF_sin,
2701 PF_cos,
2702 PF_sqrt,
2703 PF_changepitch,
2704 PF_TraceToss,
2705 PF_etos,
2706 PF_Fixme,
2707
2708 SV_MoveToGoal,
2709 PF_precache_file,
2710 PF_makestatic,
2711
2712 PF_changelevel,
2713 PF_Fixme,
2714
2715 PF_cvar_set,
2716 PF_centerprint,
2717
2718 PF_ambientsound,
2719
2720 PF_precache_model,
2721 PF_precache_sound,              // precache_sound2 is different only for qcc
2722 PF_precache_file,
2723
2724 PF_setspawnparms,
2725
2726 PF_Fixme,                               // #79 LordHavoc: dunno who owns 79-89, so these are just padding
2727 PF_Fixme,                               // #80
2728 PF_Fixme,                               // #81
2729 PF_Fixme,                               // #82
2730 PF_Fixme,                               // #83
2731 PF_Fixme,                               // #84
2732 PF_Fixme,                               // #85
2733 PF_Fixme,                               // #86
2734 PF_Fixme,                               // #87
2735 PF_Fixme,                               // #88
2736 PF_Fixme,                               // #89
2737
2738 PF_tracebox,                    // #90 LordHavoc builtin range (9x)
2739 PF_randomvec,                   // #91
2740 PF_GetLight,                    // #92
2741 PF_registercvar,                // #93
2742 PF_min,                                 // #94
2743 PF_max,                                 // #95
2744 PF_bound,                               // #96
2745 PF_pow,                                 // #97
2746 PF_FindFloat,                   // #98
2747 PF_checkextension,              // #99
2748 #define a PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme,
2749 #define aa a a a a a a a a a a
2750 aa // #200
2751 aa // #300
2752 aa // #400
2753 PF_copyentity,                  // #400 LordHavoc: builtin range (4xx)
2754 PF_setcolor,                    // #401
2755 PF_findchain,                   // #402
2756 PF_findchainfloat,              // #403
2757 PF_effect,                              // #404
2758 PF_te_blood,                    // #405
2759 PF_te_bloodshower,              // #406
2760 PF_te_explosionrgb,             // #407
2761 PF_te_particlecube,             // #408
2762 PF_te_particlerain,             // #409
2763 PF_te_particlesnow,             // #410
2764 PF_te_spark,                    // #411
2765 PF_te_gunshotquad,              // #412
2766 PF_te_spikequad,                // #413
2767 PF_te_superspikequad,   // #414
2768 PF_te_explosionquad,    // #415
2769 PF_te_smallflash,               // #416
2770 PF_te_customflash,              // #417
2771 PF_te_gunshot,                  // #418
2772 PF_te_spike,                    // #419
2773 PF_te_superspike,               // #420
2774 PF_te_explosion,                // #421
2775 PF_te_tarexplosion,             // #422
2776 PF_te_wizspike,                 // #423
2777 PF_te_knightspike,              // #424
2778 PF_te_lavasplash,               // #425
2779 PF_te_teleport,                 // #426
2780 PF_te_explosion2,               // #427
2781 PF_te_lightning1,               // #428
2782 PF_te_lightning2,               // #429
2783 PF_te_lightning3,               // #430
2784 PF_te_beam,                             // #431
2785 PF_vectorvectors,               // #432
2786 PF_te_plasmaburn,               // #433
2787 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2788 PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2789 PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2790 PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2791 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2792 PF_getsurfaceclippedpoint,// #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2793 };
2794
2795 builtin_t *pr_builtins = pr_builtin;
2796 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
2797