vertex arrays renamed to varray_ and exposed to rest of engine
[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 int SV_ModelIndex (char *name);
1755
1756 void PF_makestatic (void)
1757 {
1758         edict_t *ent;
1759         int             i, large;
1760
1761         ent = G_EDICT(OFS_PARM0);
1762
1763         large = false;
1764         if (ent->v.modelindex >= 256 || ent->v.frame >= 256)
1765                 large = true;
1766
1767         if (large)
1768         {
1769                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1770                 MSG_WriteShort (&sv.signon, ent->v.modelindex);
1771                 MSG_WriteShort (&sv.signon, ent->v.frame);
1772         }
1773         else
1774         {
1775                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1776                 MSG_WriteByte (&sv.signon, ent->v.modelindex);
1777                 MSG_WriteByte (&sv.signon, ent->v.frame);
1778         }
1779
1780         MSG_WriteByte (&sv.signon, ent->v.colormap);
1781         MSG_WriteByte (&sv.signon, ent->v.skin);
1782         for (i=0 ; i<3 ; i++)
1783         {
1784                 MSG_WriteDPCoord(&sv.signon, ent->v.origin[i]);
1785                 MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1786         }
1787
1788 // throw the entity away now
1789         ED_Free (ent);
1790 }
1791
1792 //=============================================================================
1793
1794 /*
1795 ==============
1796 PF_setspawnparms
1797 ==============
1798 */
1799 void PF_setspawnparms (void)
1800 {
1801         edict_t *ent;
1802         int             i;
1803         client_t        *client;
1804
1805         ent = G_EDICT(OFS_PARM0);
1806         i = NUM_FOR_EDICT(ent);
1807         if (i < 1 || i > svs.maxclients)
1808                 Host_Error ("Entity is not a client");
1809
1810         // copy spawn parms out of the client_t
1811         client = svs.clients + (i-1);
1812
1813         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1814                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1815 }
1816
1817 /*
1818 ==============
1819 PF_changelevel
1820 ==============
1821 */
1822 void PF_changelevel (void)
1823 {
1824         char    *s;
1825
1826 // make sure we don't issue two changelevels
1827         if (svs.changelevel_issued)
1828                 return;
1829         svs.changelevel_issued = true;
1830
1831         s = G_STRING(OFS_PARM0);
1832         Cbuf_AddText (va("changelevel %s\n",s));
1833 }
1834
1835 void PF_sin (void)
1836 {
1837         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1838 }
1839
1840 void PF_cos (void)
1841 {
1842         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1843 }
1844
1845 void PF_sqrt (void)
1846 {
1847         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1848 }
1849
1850 /*
1851 =================
1852 PF_RandomVec
1853
1854 Returns a vector of length < 1
1855
1856 randomvec()
1857 =================
1858 */
1859 void PF_randomvec (void)
1860 {
1861         vec3_t          temp;
1862         do
1863         {
1864                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1865                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1866                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1867         }
1868         while (DotProduct(temp, temp) >= 1);
1869         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1870 }
1871
1872 void SV_LightPoint (vec3_t color, vec3_t p);
1873 /*
1874 =================
1875 PF_GetLight
1876
1877 Returns a color vector indicating the lighting at the requested point.
1878
1879 (Internal Operation note: actually measures the light beneath the point, just like
1880                           the model lighting on the client)
1881
1882 getlight(vector)
1883 =================
1884 */
1885 void PF_GetLight (void)
1886 {
1887         vec3_t          color;
1888         vec_t*          p;
1889         p = G_VECTOR(OFS_PARM0);
1890         SV_LightPoint (color, p);
1891         VectorCopy (color, G_VECTOR(OFS_RETURN));
1892 }
1893
1894 #define MAX_QC_CVARS 128
1895 cvar_t qc_cvar[MAX_QC_CVARS];
1896 int currentqc_cvar;
1897
1898 void PF_registercvar (void)
1899 {
1900         char *name, *value;
1901         cvar_t *variable;
1902         name = G_STRING(OFS_PARM0);
1903         value = G_STRING(OFS_PARM1);
1904         G_FLOAT(OFS_RETURN) = 0;
1905 // first check to see if it has already been defined
1906         if (Cvar_FindVar (name))
1907                 return;
1908
1909 // check for overlap with a command
1910         if (Cmd_Exists (name))
1911         {
1912                 Con_Printf ("PF_registercvar: %s is a command\n", name);
1913                 return;
1914         }
1915
1916         if (currentqc_cvar >= MAX_QC_CVARS)
1917                 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1918
1919 // copy the name and value
1920         variable = &qc_cvar[currentqc_cvar++];
1921         variable->name = Z_Malloc (strlen(name)+1);
1922         strcpy (variable->name, name);
1923         variable->string = Z_Malloc (strlen(value)+1);
1924         strcpy (variable->string, value);
1925         variable->value = atof (value);
1926
1927         Cvar_RegisterVariable(variable);
1928         G_FLOAT(OFS_RETURN) = 1; // success
1929 }
1930
1931 /*
1932 =================
1933 PF_min
1934
1935 returns the minimum of two supplied floats
1936
1937 min(a, b)
1938 =================
1939 */
1940 void PF_min (void)
1941 {
1942         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1943         if (pr_argc == 2)
1944                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1945         else if (pr_argc >= 3)
1946         {
1947                 int i;
1948                 float f = G_FLOAT(OFS_PARM0);
1949                 for (i = 1;i < pr_argc;i++)
1950                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
1951                                 f = G_FLOAT((OFS_PARM0+i*3));
1952                 G_FLOAT(OFS_RETURN) = f;
1953         }
1954         else
1955                 Host_Error("min: must supply at least 2 floats\n");
1956 }
1957
1958 /*
1959 =================
1960 PF_max
1961
1962 returns the maximum of two supplied floats
1963
1964 max(a, b)
1965 =================
1966 */
1967 void PF_max (void)
1968 {
1969         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1970         if (pr_argc == 2)
1971                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1972         else if (pr_argc >= 3)
1973         {
1974                 int i;
1975                 float f = G_FLOAT(OFS_PARM0);
1976                 for (i = 1;i < pr_argc;i++)
1977                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
1978                                 f = G_FLOAT((OFS_PARM0+i*3));
1979                 G_FLOAT(OFS_RETURN) = f;
1980         }
1981         else
1982                 Host_Error("max: must supply at least 2 floats\n");
1983 }
1984
1985 /*
1986 =================
1987 PF_bound
1988
1989 returns number bounded by supplied range
1990
1991 min(min, value, max)
1992 =================
1993 */
1994 void PF_bound (void)
1995 {
1996         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
1997 }
1998
1999 /*
2000 =================
2001 PF_pow
2002
2003 returns a raised to power b
2004
2005 pow(a, b)
2006 =================
2007 */
2008 void PF_pow (void)
2009 {
2010         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2011 }
2012
2013 /*
2014 =================
2015 PF_copyentity
2016
2017 copies data from one entity to another
2018
2019 copyentity(src, dst)
2020 =================
2021 */
2022 void PF_copyentity (void)
2023 {
2024         edict_t *in, *out;
2025         in = G_EDICT(OFS_PARM0);
2026         out = G_EDICT(OFS_PARM1);
2027         memcpy(out, in, pr_edict_size);
2028 }
2029
2030 /*
2031 =================
2032 PF_setcolor
2033
2034 sets the color of a client and broadcasts the update to all connected clients
2035
2036 setcolor(clientent, value)
2037 =================
2038 */
2039 void PF_setcolor (void)
2040 {
2041         client_t        *client;
2042         int                     entnum, i;
2043
2044         entnum = G_EDICTNUM(OFS_PARM0);
2045         i = G_FLOAT(OFS_PARM1);
2046
2047         if (entnum < 1 || entnum > svs.maxclients)
2048         {
2049                 Con_Printf ("tried to setcolor a non-client\n");
2050                 return;
2051         }
2052
2053         client = &svs.clients[entnum-1];
2054         client->colors = i;
2055         client->edict->v.team = (i & 15) + 1;
2056
2057         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2058         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2059         MSG_WriteByte (&sv.reliable_datagram, i);
2060 }
2061
2062 /*
2063 =================
2064 PF_effect
2065
2066 effect(origin, modelname, startframe, framecount, framerate)
2067 =================
2068 */
2069 void PF_effect (void)
2070 {
2071         char *s;
2072         s = G_STRING(OFS_PARM1);
2073         if (!s || !s[0])
2074                 Host_Error("effect: no model specified\n");
2075
2076         SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2077 }
2078
2079 void PF_te_blood (void)
2080 {
2081         if (G_FLOAT(OFS_PARM2) < 1)
2082                 return;
2083         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2084         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2085         // origin
2086         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2087         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2088         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2089         // velocity
2090         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2091         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2092         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2093         // count
2094         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2095 }
2096
2097 void PF_te_bloodshower (void)
2098 {
2099         if (G_FLOAT(OFS_PARM3) < 1)
2100                 return;
2101         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2102         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2103         // min
2104         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2105         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2106         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2107         // max
2108         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2109         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2110         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2111         // speed
2112         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2113         // count
2114         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2115 }
2116
2117 void PF_te_explosionrgb (void)
2118 {
2119         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2120         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2121         // origin
2122         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2123         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2124         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2125         // color
2126         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2127         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2128         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2129 }
2130
2131 void PF_te_particlecube (void)
2132 {
2133         if (G_FLOAT(OFS_PARM3) < 1)
2134                 return;
2135         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2136         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2137         // min
2138         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2139         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2140         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2141         // max
2142         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2143         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2144         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2145         // velocity
2146         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2147         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2148         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2149         // count
2150         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2151         // color
2152         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2153         // gravity true/false
2154         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2155         // randomvel
2156         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2157 }
2158
2159 void PF_te_particlerain (void)
2160 {
2161         if (G_FLOAT(OFS_PARM3) < 1)
2162                 return;
2163         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2164         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2165         // min
2166         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2167         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2168         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2169         // max
2170         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2171         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2172         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2173         // velocity
2174         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2175         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2176         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2177         // count
2178         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2179         // color
2180         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2181 }
2182
2183 void PF_te_particlesnow (void)
2184 {
2185         if (G_FLOAT(OFS_PARM3) < 1)
2186                 return;
2187         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2188         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2189         // min
2190         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2191         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2192         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2193         // max
2194         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2195         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2196         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2197         // velocity
2198         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2199         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2200         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2201         // count
2202         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2203         // color
2204         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2205 }
2206
2207 void PF_te_spark (void)
2208 {
2209         if (G_FLOAT(OFS_PARM2) < 1)
2210                 return;
2211         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2212         MSG_WriteByte(&sv.datagram, TE_SPARK);
2213         // origin
2214         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2215         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2216         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2217         // velocity
2218         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2219         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2220         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2221         // count
2222         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2223 }
2224
2225 void PF_te_gunshotquad (void)
2226 {
2227         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2228         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2229         // origin
2230         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2231         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2232         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2233 }
2234
2235 void PF_te_spikequad (void)
2236 {
2237         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2238         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2239         // origin
2240         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2241         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2242         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2243 }
2244
2245 void PF_te_superspikequad (void)
2246 {
2247         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2248         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2249         // origin
2250         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2251         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2252         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2253 }
2254
2255 void PF_te_explosionquad (void)
2256 {
2257         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2258         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2259         // origin
2260         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2261         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2262         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2263 }
2264
2265 void PF_te_smallflash (void)
2266 {
2267         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2268         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2269         // origin
2270         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2271         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2272         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2273 }
2274
2275 void PF_te_customflash (void)
2276 {
2277         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2278                 return;
2279         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2280         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2281         // origin
2282         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2283         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2284         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2285         // radius
2286         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2287         // lifetime
2288         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2289         // color
2290         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2291         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2292         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2293 }
2294
2295 void PF_te_gunshot (void)
2296 {
2297         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2298         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2299         // origin
2300         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2301         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2302         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2303 }
2304
2305 void PF_te_spike (void)
2306 {
2307         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2308         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2309         // origin
2310         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2311         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2312         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2313 }
2314
2315 void PF_te_superspike (void)
2316 {
2317         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2318         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2319         // origin
2320         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2321         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2322         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2323 }
2324
2325 void PF_te_explosion (void)
2326 {
2327         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2328         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2329         // origin
2330         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2331         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2332         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2333 }
2334
2335 void PF_te_tarexplosion (void)
2336 {
2337         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2338         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2339         // origin
2340         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2341         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2342         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2343 }
2344
2345 void PF_te_wizspike (void)
2346 {
2347         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2349         // origin
2350         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2351         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2352         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2353 }
2354
2355 void PF_te_knightspike (void)
2356 {
2357         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2358         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2359         // origin
2360         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2361         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2362         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2363 }
2364
2365 void PF_te_lavasplash (void)
2366 {
2367         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2368         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2369         // origin
2370         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2371         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2372         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2373 }
2374
2375 void PF_te_teleport (void)
2376 {
2377         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2378         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2379         // origin
2380         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2381         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2382         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2383 }
2384
2385 void PF_te_explosion2 (void)
2386 {
2387         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2388         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2389         // origin
2390         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2391         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2392         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2393         // color
2394         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2395 }
2396
2397 void PF_te_lightning1 (void)
2398 {
2399         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2400         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2401         // owner entity
2402         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2403         // start
2404         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2405         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2406         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2407         // end
2408         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2409         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2410         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2411 }
2412
2413 void PF_te_lightning2 (void)
2414 {
2415         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2416         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2417         // owner entity
2418         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2419         // start
2420         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2421         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2422         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2423         // end
2424         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2425         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2426         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2427 }
2428
2429 void PF_te_lightning3 (void)
2430 {
2431         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2432         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2433         // owner entity
2434         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2435         // start
2436         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2437         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2438         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2439         // end
2440         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2441         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2442         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2443 }
2444
2445 void PF_te_beam (void)
2446 {
2447         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2448         MSG_WriteByte(&sv.datagram, TE_BEAM);
2449         // owner entity
2450         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2451         // start
2452         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2453         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2454         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2455         // end
2456         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2457         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2458         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2459 }
2460
2461 void PF_te_plasmaburn (void)
2462 {
2463         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2464         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2465         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2466         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2467         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2468 }
2469
2470 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2471 {
2472         int i, j;
2473         vec3_t v1, clipplanenormal, normal;
2474         vec_t clipplanedist, clipdist;
2475         VectorCopy(p, out);
2476         if (surf->flags & SURF_PLANEBACK)
2477                 VectorNegate(surf->plane->normal, normal);
2478         else
2479                 VectorCopy(surf->plane->normal, normal);
2480         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2481         {
2482                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2483                 VectorNormalizeFast(v1);
2484                 CrossProduct(v1, normal, clipplanenormal);
2485                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2486                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2487                 if (clipdist > 0)
2488                 {
2489                         clipdist = -clipdist;
2490                         VectorMA(out, clipdist, clipplanenormal, out);
2491                 }
2492         }
2493 }
2494
2495 static msurface_t *getsurface(edict_t *ed, int surfnum)
2496 {
2497         int modelindex;
2498         model_t *model;
2499         if (!ed || ed->free)
2500                 return NULL;
2501         modelindex = ed->v.modelindex;
2502         if (modelindex < 1 || modelindex >= MAX_MODELS)
2503                 return NULL;
2504         model = sv.models[modelindex];
2505         if (model->type != mod_brush)
2506                 return NULL;
2507         if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2508                 return NULL;
2509         return model->surfaces + surfnum + model->firstmodelsurface;
2510 }
2511
2512
2513 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2514 void PF_getsurfacenumpoints(void)
2515 {
2516         msurface_t *surf;
2517         // return 0 if no such surface
2518         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2519         {
2520                 G_FLOAT(OFS_RETURN) = 0;
2521                 return;
2522         }
2523
2524         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2525 }
2526 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2527 void PF_getsurfacepoint(void)
2528 {
2529         edict_t *ed;
2530         msurface_t *surf;
2531         int pointnum;
2532         VectorClear(G_VECTOR(OFS_RETURN));
2533         ed = G_EDICT(OFS_PARM0);
2534         if (!ed || ed->free)
2535                 return;
2536         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2537                 return;
2538         pointnum = G_FLOAT(OFS_PARM2);
2539         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2540                 return;
2541         // FIXME: implement rotation/scaling
2542         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v.origin, G_VECTOR(OFS_RETURN));
2543 }
2544 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2545 void PF_getsurfacenormal(void)
2546 {
2547         msurface_t *surf;
2548         VectorClear(G_VECTOR(OFS_RETURN));
2549         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2550                 return;
2551         // FIXME: implement rotation/scaling
2552         if (surf->flags & SURF_PLANEBACK)
2553                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2554         else
2555                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2556 }
2557 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2558 void PF_getsurfacetexture(void)
2559 {
2560         msurface_t *surf;
2561         G_INT(OFS_RETURN) = 0;
2562         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2563                 return;
2564         G_INT(OFS_RETURN) = surf->texinfo->texture->name - pr_strings;
2565 }
2566 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2567 void PF_getsurfacenearpoint(void)
2568 {
2569         int surfnum, best, modelindex;
2570         vec3_t clipped, p;
2571         vec_t dist, bestdist;
2572         edict_t *ed;
2573         model_t *model;
2574         msurface_t *surf;
2575         vec_t *point;
2576         G_FLOAT(OFS_RETURN) = -1;
2577         ed = G_EDICT(OFS_PARM0);
2578         point = G_VECTOR(OFS_PARM1);
2579
2580         if (!ed || ed->free)
2581                 return;
2582         modelindex = ed->v.modelindex;
2583         if (modelindex < 1 || modelindex >= MAX_MODELS)
2584                 return;
2585         model = sv.models[modelindex];
2586         if (model->type != mod_brush)
2587                 return;
2588
2589         // FIXME: implement rotation/scaling
2590         VectorSubtract(point, ed->v.origin, p);
2591         best = -1;
2592         bestdist = 1000000000;
2593         for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2594         {
2595                 surf = model->surfaces + surfnum + model->firstmodelsurface;
2596                 dist = PlaneDiff(p, surf->plane);
2597                 dist = dist * dist;
2598                 if (dist < bestdist)
2599                 {
2600                         clippointtosurface(surf, p, clipped);
2601                         VectorSubtract(clipped, p, clipped);
2602                         dist += DotProduct(clipped, clipped);
2603                         if (dist < bestdist)
2604                         {
2605                                 best = surfnum;
2606                                 bestdist = dist;
2607                         }
2608                 }
2609         }
2610         G_FLOAT(OFS_RETURN) = best;
2611 }
2612 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2613 void PF_getsurfaceclippedpoint(void)
2614 {
2615         edict_t *ed;
2616         msurface_t *surf;
2617         vec3_t p, out;
2618         VectorClear(G_VECTOR(OFS_RETURN));
2619         ed = G_EDICT(OFS_PARM0);
2620         if (!ed || ed->free)
2621                 return;
2622         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2623                 return;
2624         // FIXME: implement rotation/scaling
2625         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v.origin, p);
2626         clippointtosurface(surf, p, out);
2627         // FIXME: implement rotation/scaling
2628         VectorAdd(out, ed->v.origin, G_VECTOR(OFS_RETURN));
2629 }
2630
2631 void PF_Fixme (void)
2632 {
2633         Host_Error ("unimplemented QC builtin"); // LordHavoc: was misspelled (bulitin)
2634 }
2635
2636
2637
2638 builtin_t pr_builtin[] =
2639 {
2640 PF_Fixme,
2641 PF_makevectors, // void(entity e)       makevectors             = #1;
2642 PF_setorigin,   // void(entity e, vector o) setorigin   = #2;
2643 PF_setmodel,    // void(entity e, string m) setmodel    = #3;
2644 PF_setsize,     // void(entity e, vector min, vector max) setsize = #4;
2645 PF_Fixme,       // void(entity e, vector min, vector max) setabssize = #5;
2646 PF_break,       // void() break                                         = #6;
2647 PF_random,      // float() random                                               = #7;
2648 PF_sound,       // void(entity e, float chan, string samp) sound = #8;
2649 PF_normalize,   // vector(vector v) normalize                   = #9;
2650 PF_error,       // void(string e) error                         = #10;
2651 PF_objerror,    // void(string e) objerror                              = #11;
2652 PF_vlen,        // float(vector v) vlen                         = #12;
2653 PF_vectoyaw,    // float(vector v) vectoyaw             = #13;
2654 PF_Spawn,       // entity() spawn                                               = #14;
2655 PF_Remove,      // void(entity e) remove                                = #15;
2656 PF_traceline,   // float(vector v1, vector v2, float tryents) traceline = #16;
2657 PF_checkclient, // entity() clientlist                                  = #17;
2658 PF_Find,        // entity(entity start, .string fld, string match) find = #18;
2659 PF_precache_sound,      // void(string s) precache_sound                = #19;
2660 PF_precache_model,      // void(string s) precache_model                = #20;
2661 PF_stuffcmd,    // void(entity client, string s)stuffcmd = #21;
2662 PF_findradius,  // entity(vector org, float rad) findradius = #22;
2663 PF_bprint,      // void(string s) bprint                                = #23;
2664 PF_sprint,      // void(entity client, string s) sprint = #24;
2665 PF_dprint,      // void(string s) dprint                                = #25;
2666 PF_ftos,        // void(string s) ftos                          = #26;
2667 PF_vtos,        // void(string s) vtos                          = #27;
2668 PF_coredump,
2669 PF_traceon,
2670 PF_traceoff,
2671 PF_eprint,      // void(entity e) debug print an entire entity
2672 PF_walkmove, // float(float yaw, float dist) walkmove
2673 PF_Fixme, // float(float yaw, float dist) walkmove
2674 PF_droptofloor,
2675 PF_lightstyle,
2676 PF_rint,
2677 PF_floor,
2678 PF_ceil,
2679 PF_Fixme,
2680 PF_checkbottom,
2681 PF_pointcontents,
2682 PF_Fixme,
2683 PF_fabs,
2684 PF_aim,
2685 PF_cvar,
2686 PF_localcmd,
2687 PF_nextent,
2688 PF_particle,
2689 PF_changeyaw,
2690 PF_Fixme,
2691 PF_vectoangles,
2692
2693 PF_WriteByte,
2694 PF_WriteChar,
2695 PF_WriteShort,
2696 PF_WriteLong,
2697 PF_WriteCoord,
2698 PF_WriteAngle,
2699 PF_WriteString,
2700 PF_WriteEntity,
2701
2702 PF_sin,
2703 PF_cos,
2704 PF_sqrt,
2705 PF_changepitch,
2706 PF_TraceToss,
2707 PF_etos,
2708 PF_Fixme,
2709
2710 SV_MoveToGoal,
2711 PF_precache_file,
2712 PF_makestatic,
2713
2714 PF_changelevel,
2715 PF_Fixme,
2716
2717 PF_cvar_set,
2718 PF_centerprint,
2719
2720 PF_ambientsound,
2721
2722 PF_precache_model,
2723 PF_precache_sound,              // precache_sound2 is different only for qcc
2724 PF_precache_file,
2725
2726 PF_setspawnparms,
2727
2728 PF_Fixme,                               // #79 LordHavoc: dunno who owns 79-89, so these are just padding
2729 PF_Fixme,                               // #80
2730 PF_Fixme,                               // #81
2731 PF_Fixme,                               // #82
2732 PF_Fixme,                               // #83
2733 PF_Fixme,                               // #84
2734 PF_Fixme,                               // #85
2735 PF_Fixme,                               // #86
2736 PF_Fixme,                               // #87
2737 PF_Fixme,                               // #88
2738 PF_Fixme,                               // #89
2739
2740 PF_tracebox,                    // #90 LordHavoc builtin range (9x)
2741 PF_randomvec,                   // #91
2742 PF_GetLight,                    // #92
2743 PF_registercvar,                // #93
2744 PF_min,                                 // #94
2745 PF_max,                                 // #95
2746 PF_bound,                               // #96
2747 PF_pow,                                 // #97
2748 PF_FindFloat,                   // #98
2749 PF_checkextension,              // #99
2750 #define a PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme,
2751 #define aa a a a a a a a a a a
2752 aa // #200
2753 aa // #300
2754 aa // #400
2755 PF_copyentity,                  // #400 LordHavoc: builtin range (4xx)
2756 PF_setcolor,                    // #401
2757 PF_findchain,                   // #402
2758 PF_findchainfloat,              // #403
2759 PF_effect,                              // #404
2760 PF_te_blood,                    // #405
2761 PF_te_bloodshower,              // #406
2762 PF_te_explosionrgb,             // #407
2763 PF_te_particlecube,             // #408
2764 PF_te_particlerain,             // #409
2765 PF_te_particlesnow,             // #410
2766 PF_te_spark,                    // #411
2767 PF_te_gunshotquad,              // #412
2768 PF_te_spikequad,                // #413
2769 PF_te_superspikequad,   // #414
2770 PF_te_explosionquad,    // #415
2771 PF_te_smallflash,               // #416
2772 PF_te_customflash,              // #417
2773 PF_te_gunshot,                  // #418
2774 PF_te_spike,                    // #419
2775 PF_te_superspike,               // #420
2776 PF_te_explosion,                // #421
2777 PF_te_tarexplosion,             // #422
2778 PF_te_wizspike,                 // #423
2779 PF_te_knightspike,              // #424
2780 PF_te_lavasplash,               // #425
2781 PF_te_teleport,                 // #426
2782 PF_te_explosion2,               // #427
2783 PF_te_lightning1,               // #428
2784 PF_te_lightning2,               // #429
2785 PF_te_lightning3,               // #430
2786 PF_te_beam,                             // #431
2787 PF_vectorvectors,               // #432
2788 PF_te_plasmaburn,               // #433
2789 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2790 PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2791 PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2792 PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2793 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2794 PF_getsurfaceclippedpoint,// #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2795 };
2796
2797 builtin_t *pr_builtins = pr_builtin;
2798 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
2799