]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - pr_cmds.c
make sure zFar is at least 64 units to avoid feeding a bogus value to glFrustum
[xonotic/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t  sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24
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                         PR_RunError ("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                 PR_RunError ("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         PR_RunError ("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         l = (leaf - sv.worldmodel->leafs) - 1;
873         if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
874         {
875 c_notvis++;
876                 RETURN_EDICT(sv.edicts);
877                 return;
878         }
879
880 // might be able to see it
881 c_invis++;
882         RETURN_EDICT(ent);
883 }
884
885 //============================================================================
886
887
888 /*
889 =================
890 PF_stuffcmd
891
892 Sends text over to the client's execution buffer
893
894 stuffcmd (clientent, value)
895 =================
896 */
897 void PF_stuffcmd (void)
898 {
899         int             entnum;
900         char    *str;
901         client_t        *old;
902         
903         entnum = G_EDICTNUM(OFS_PARM0);
904         if (entnum < 1 || entnum > svs.maxclients)
905                 PR_RunError ("Parm 0 not a client");
906         str = G_STRING(OFS_PARM1);      
907         
908         old = host_client;
909         host_client = &svs.clients[entnum-1];
910         Host_ClientCommands ("%s", str);
911         host_client = old;
912 }
913
914 /*
915 =================
916 PF_localcmd
917
918 Sends text over to the client's execution buffer
919
920 localcmd (string)
921 =================
922 */
923 void PF_localcmd (void)
924 {
925         char    *str;
926
927         str = G_STRING(OFS_PARM0);      
928         Cbuf_AddText (str);
929 }
930
931 /*
932 =================
933 PF_cvar
934
935 float cvar (string)
936 =================
937 */
938 void PF_cvar (void)
939 {
940         char    *str;
941         
942         str = G_STRING(OFS_PARM0);
943         
944         G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
945 }
946
947 /*
948 =================
949 PF_cvar_set
950
951 float cvar (string)
952 =================
953 */
954 void PF_cvar_set (void)
955 {
956         char    *var, *val;
957         
958         var = G_STRING(OFS_PARM0);
959         val = G_STRING(OFS_PARM1);
960         
961         Cvar_Set (var, val);
962 }
963
964 /*
965 =================
966 PF_findradius
967
968 Returns a chain of entities that have origins within a spherical area
969
970 findradius (origin, radius)
971 =================
972 */
973 void PF_findradius (void)
974 {
975         edict_t *ent, *chain;
976         float radius;
977         float radius2;
978         float *org;
979         float eorg[3];
980         int i;
981
982         chain = (edict_t *)sv.edicts;
983         
984         org = G_VECTOR(OFS_PARM0);
985         radius = G_FLOAT(OFS_PARM1);
986         radius2 = radius * radius;
987
988         ent = NEXT_EDICT(sv.edicts);
989         for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
990         {
991                 if (ent->free)
992                         continue;
993                 if (ent->v.solid == SOLID_NOT)
994                         continue;
995
996                 // LordHavoc: compare against bounding box rather than center,
997                 // and use DotProduct instead of Length, major speedup
998                 eorg[0] = (org[0] - ent->v.origin[0]) - bound(ent->v.mins[0], (org[0] - ent->v.origin[0]), ent->v.maxs[0]);
999                 eorg[1] = (org[1] - ent->v.origin[1]) - bound(ent->v.mins[1], (org[1] - ent->v.origin[1]), ent->v.maxs[1]);
1000                 eorg[2] = (org[2] - ent->v.origin[2]) - bound(ent->v.mins[2], (org[2] - ent->v.origin[2]), ent->v.maxs[2]);
1001                 if (DotProduct(eorg, eorg) > radius2)
1002                         continue;
1003                         
1004                 ent->v.chain = EDICT_TO_PROG(chain);
1005                 chain = ent;
1006         }
1007
1008         RETURN_EDICT(chain);
1009 }
1010
1011
1012 /*
1013 =========
1014 PF_dprint
1015 =========
1016 */
1017 void PF_dprint (void)
1018 {
1019         Con_DPrintf ("%s",PF_VarString(0));
1020 }
1021
1022 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1023 #define STRINGTEMP_BUFFERS 16
1024 #define STRINGTEMP_LENGTH 128
1025 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1026 static int pr_string_tempindex = 0;
1027
1028 static char *PR_GetTempString(void)
1029 {
1030         char *s;
1031         s = pr_string_temp[pr_string_tempindex];
1032         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1033         return s;
1034 }
1035
1036 void PF_ftos (void)
1037 {
1038         float v;
1039         char *s;
1040         v = G_FLOAT(OFS_PARM0);
1041
1042         s = PR_GetTempString();
1043         // LordHavoc: ftos improvement
1044         sprintf (s, "%g", v);
1045         G_INT(OFS_RETURN) = s - pr_strings;
1046 }
1047
1048 void PF_fabs (void)
1049 {
1050         float   v;
1051         v = G_FLOAT(OFS_PARM0);
1052         G_FLOAT(OFS_RETURN) = fabs(v);
1053 }
1054
1055 void PF_vtos (void)
1056 {
1057         char *s;
1058         s = PR_GetTempString();
1059         sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1060         G_INT(OFS_RETURN) = s - pr_strings;
1061 }
1062
1063 void PF_etos (void)
1064 {
1065         char *s;
1066         s = PR_GetTempString();
1067         sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1068         G_INT(OFS_RETURN) = s - pr_strings;
1069 }
1070
1071 void PF_Spawn (void)
1072 {
1073         edict_t *ed;
1074         ed = ED_Alloc();
1075         RETURN_EDICT(ed);
1076 }
1077
1078 void PF_Remove (void)
1079 {
1080         edict_t *ed;
1081
1082         ed = G_EDICT(OFS_PARM0);
1083         if (ed == sv.edicts)
1084                 PR_RunError("remove: tried to remove world\n");
1085         if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1086                 PR_RunError("remove: tried to remove a client\n");
1087         ED_Free (ed);
1088 }
1089
1090
1091 // entity (entity start, .string field, string match) find = #5;
1092 void PF_Find (void)
1093 {
1094         int             e;
1095         int             f;
1096         char    *s, *t;
1097         edict_t *ed;
1098
1099         e = G_EDICTNUM(OFS_PARM0);
1100         f = G_INT(OFS_PARM1);
1101         s = G_STRING(OFS_PARM2);
1102         if (!s || !s[0])
1103         {
1104                 RETURN_EDICT(sv.edicts);
1105                 return;
1106         }
1107
1108         for (e++ ; e < sv.num_edicts ; e++)
1109         {
1110                 ed = EDICT_NUM(e);
1111                 if (ed->free)
1112                         continue;
1113                 t = E_STRING(ed,f);
1114                 if (!t)
1115                         continue;
1116                 if (!strcmp(t,s))
1117                 {
1118                         RETURN_EDICT(ed);
1119                         return;
1120                 }
1121         }
1122
1123         RETURN_EDICT(sv.edicts);
1124 }
1125
1126 // LordHavoc: added this for searching float, int, and entity reference fields
1127 void PF_FindFloat (void)
1128 {
1129         int             e;      
1130         int             f;
1131         float   s;
1132         edict_t *ed;
1133
1134         e = G_EDICTNUM(OFS_PARM0);
1135         f = G_INT(OFS_PARM1);
1136         s = G_FLOAT(OFS_PARM2);
1137                 
1138         for (e++ ; e < sv.num_edicts ; e++)
1139         {
1140                 ed = EDICT_NUM(e);
1141                 if (ed->free)
1142                         continue;
1143                 if (E_FLOAT(ed,f) == s)
1144                 {
1145                         RETURN_EDICT(ed);
1146                         return;
1147                 }
1148         }
1149
1150         RETURN_EDICT(sv.edicts);
1151 }
1152
1153 // chained search for strings in entity fields
1154 // entity(.string field, string match) findchain = #402;
1155 void PF_findchain (void)
1156 {
1157         int             i;      
1158         int             f;
1159         char    *s, *t;
1160         edict_t *ent, *chain;
1161
1162         chain = (edict_t *)sv.edicts;
1163
1164         f = G_INT(OFS_PARM0);
1165         s = G_STRING(OFS_PARM1);
1166         if (!s || !s[0])
1167         {
1168                 RETURN_EDICT(sv.edicts);
1169                 return;
1170         }
1171                 
1172         ent = NEXT_EDICT(sv.edicts);
1173         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1174         {
1175                 if (ent->free)
1176                         continue;
1177                 t = E_STRING(ent,f);
1178                 if (!t)
1179                         continue;
1180                 if (strcmp(t,s))
1181                         continue;
1182
1183                 ent->v.chain = EDICT_TO_PROG(chain);
1184                 chain = ent;
1185         }
1186
1187         RETURN_EDICT(chain);
1188 }
1189
1190 // LordHavoc: chained search for float, int, and entity reference fields
1191 // entity(.string field, float match) findchainfloat = #403;
1192 void PF_findchainfloat (void)
1193 {
1194         int             i;      
1195         int             f;
1196         float   s;
1197         edict_t *ent, *chain;
1198
1199         chain = (edict_t *)sv.edicts;
1200
1201         f = G_INT(OFS_PARM0);
1202         s = G_FLOAT(OFS_PARM1);
1203                 
1204         ent = NEXT_EDICT(sv.edicts);
1205         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1206         {
1207                 if (ent->free)
1208                         continue;
1209                 if (E_FLOAT(ent,f) != s)
1210                         continue;
1211
1212                 ent->v.chain = EDICT_TO_PROG(chain);
1213                 chain = ent;
1214         }
1215
1216         RETURN_EDICT(chain);
1217 }
1218
1219 void PR_CheckEmptyString (char *s)
1220 {
1221         if (s[0] <= ' ')
1222                 PR_RunError ("Bad string");
1223 }
1224
1225 void PF_precache_file (void)
1226 {       // precache_file is only used to copy files with qcc, it does nothing
1227         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1228 }
1229
1230 void PF_precache_sound (void)
1231 {
1232         char    *s;
1233         int             i;
1234
1235         if (sv.state != ss_loading)
1236                 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1237
1238         s = G_STRING(OFS_PARM0);
1239         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1240         PR_CheckEmptyString (s);
1241         
1242         for (i=0 ; i<MAX_SOUNDS ; i++)
1243         {
1244                 if (!sv.sound_precache[i])
1245                 {
1246                         sv.sound_precache[i] = s;
1247                         return;
1248                 }
1249                 if (!strcmp(sv.sound_precache[i], s))
1250                         return;
1251         }
1252         PR_RunError ("PF_precache_sound: overflow");
1253 }
1254
1255 void PF_precache_model (void)
1256 {
1257         char    *s;
1258         int             i;
1259         
1260         if (sv.state != ss_loading)
1261                 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1262
1263         s = G_STRING(OFS_PARM0);
1264         if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1265                 return;
1266         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1267         PR_CheckEmptyString (s);
1268
1269         for (i=0 ; i<MAX_MODELS ; i++)
1270         {
1271                 if (!sv.model_precache[i])
1272                 {
1273                         sv.model_precache[i] = s;
1274                         sv.models[i] = Mod_ForName (s, true, false, false);
1275                         return;
1276                 }
1277                 if (!strcmp(sv.model_precache[i], s))
1278                         return;
1279         }
1280         PR_RunError ("PF_precache_model: overflow");
1281 }
1282
1283
1284 void PF_coredump (void)
1285 {
1286         ED_PrintEdicts ();
1287 }
1288
1289 void PF_traceon (void)
1290 {
1291         pr_trace = true;
1292 }
1293
1294 void PF_traceoff (void)
1295 {
1296         pr_trace = false;
1297 }
1298
1299 void PF_eprint (void)
1300 {
1301         ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1302 }
1303
1304 /*
1305 ===============
1306 PF_walkmove
1307
1308 float(float yaw, float dist) walkmove
1309 ===============
1310 */
1311 void PF_walkmove (void)
1312 {
1313         edict_t *ent;
1314         float   yaw, dist;
1315         vec3_t  move;
1316         dfunction_t     *oldf;
1317         int     oldself;
1318         
1319         ent = PROG_TO_EDICT(pr_global_struct->self);
1320         yaw = G_FLOAT(OFS_PARM0);
1321         dist = G_FLOAT(OFS_PARM1);
1322         
1323         if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1324         {
1325                 G_FLOAT(OFS_RETURN) = 0;
1326                 return;
1327         }
1328
1329         yaw = yaw*M_PI*2 / 360;
1330         
1331         move[0] = cos(yaw)*dist;
1332         move[1] = sin(yaw)*dist;
1333         move[2] = 0;
1334
1335 // save program state, because SV_movestep may call other progs
1336         oldf = pr_xfunction;
1337         oldself = pr_global_struct->self;
1338         
1339         G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1340         
1341         
1342 // restore program state
1343         pr_xfunction = oldf;
1344         pr_global_struct->self = oldself;
1345 }
1346
1347 /*
1348 ===============
1349 PF_droptofloor
1350
1351 void() droptofloor
1352 ===============
1353 */
1354 void PF_droptofloor (void)
1355 {
1356         edict_t         *ent;
1357         vec3_t          end;
1358         trace_t         trace;
1359
1360         ent = PROG_TO_EDICT(pr_global_struct->self);
1361
1362         VectorCopy (ent->v.origin, end);
1363         end[2] -= 256;
1364
1365         trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
1366
1367         if (trace.fraction == 1 || trace.allsolid)
1368                 G_FLOAT(OFS_RETURN) = 0;
1369         else
1370         {
1371                 VectorCopy (trace.endpos, ent->v.origin);
1372                 SV_LinkEdict (ent, false);
1373                 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1374                 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1375                 G_FLOAT(OFS_RETURN) = 1;
1376                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1377                 ent->suspendedinairflag = true;
1378         }
1379 }
1380
1381 /*
1382 ===============
1383 PF_lightstyle
1384
1385 void(float style, string value) lightstyle
1386 ===============
1387 */
1388 void PF_lightstyle (void)
1389 {
1390         int             style;
1391         char    *val;
1392         client_t        *client;
1393         int                     j;
1394
1395         style = G_FLOAT(OFS_PARM0);
1396         val = G_STRING(OFS_PARM1);
1397
1398 // change the string in sv
1399         sv.lightstyles[style] = val;
1400
1401 // send message to all clients on this server
1402         if (sv.state != ss_active)
1403                 return;
1404
1405         for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1406                 if (client->active || client->spawned)
1407                 {
1408                         MSG_WriteChar (&client->message, svc_lightstyle);
1409                         MSG_WriteChar (&client->message,style);
1410                         MSG_WriteString (&client->message, val);
1411                 }
1412 }
1413
1414 void PF_rint (void)
1415 {
1416         float   f;
1417         f = G_FLOAT(OFS_PARM0);
1418         if (f > 0)
1419                 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1420         else
1421                 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1422 }
1423 void PF_floor (void)
1424 {
1425         G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1426 }
1427 void PF_ceil (void)
1428 {
1429         G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1430 }
1431
1432
1433 /*
1434 =============
1435 PF_checkbottom
1436 =============
1437 */
1438 void PF_checkbottom (void)
1439 {
1440         G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1441 }
1442
1443 /*
1444 =============
1445 PF_pointcontents
1446 =============
1447 */
1448 void PF_pointcontents (void)
1449 {
1450         G_FLOAT(OFS_RETURN) = Mod_PointInLeaf(G_VECTOR(OFS_PARM0), sv.worldmodel)->contents;
1451 }
1452
1453 /*
1454 =============
1455 PF_nextent
1456
1457 entity nextent(entity)
1458 =============
1459 */
1460 void PF_nextent (void)
1461 {
1462         int             i;
1463         edict_t *ent;
1464
1465         i = G_EDICTNUM(OFS_PARM0);
1466         while (1)
1467         {
1468                 i++;
1469                 if (i == sv.num_edicts)
1470                 {
1471                         RETURN_EDICT(sv.edicts);
1472                         return;
1473                 }
1474                 ent = EDICT_NUM(i);
1475                 if (!ent->free)
1476                 {
1477                         RETURN_EDICT(ent);
1478                         return;
1479                 }
1480         }
1481 }
1482
1483 /*
1484 =============
1485 PF_aim
1486
1487 Pick a vector for the player to shoot along
1488 vector aim(entity, missilespeed)
1489 =============
1490 */
1491 void PF_aim (void)
1492 {
1493         edict_t *ent, *check, *bestent;
1494         vec3_t  start, dir, end, bestdir;
1495         int             i, j;
1496         trace_t tr;
1497         float   dist, bestdist;
1498         float   speed;
1499
1500         ent = G_EDICT(OFS_PARM0);
1501         speed = G_FLOAT(OFS_PARM1);
1502
1503         VectorCopy (ent->v.origin, start);
1504         start[2] += 20;
1505
1506 // try sending a trace straight
1507         VectorCopy (pr_global_struct->v_forward, dir);
1508         VectorMA (start, 2048, dir, end);
1509         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1510         if (tr.ent && ((edict_t *)tr.ent)->v.takedamage == DAMAGE_AIM
1511         && (!teamplay.integer || ent->v.team <=0 || ent->v.team != ((edict_t *)tr.ent)->v.team) )
1512         {
1513                 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1514                 return;
1515         }
1516
1517
1518 // try all possible entities
1519         VectorCopy (dir, bestdir);
1520         bestdist = sv_aim.value;
1521         bestent = NULL;
1522
1523         check = NEXT_EDICT(sv.edicts);
1524         for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1525         {
1526                 if (check->v.takedamage != DAMAGE_AIM)
1527                         continue;
1528                 if (check == ent)
1529                         continue;
1530                 if (teamplay.integer && ent->v.team > 0 && ent->v.team == check->v.team)
1531                         continue;       // don't aim at teammate
1532                 for (j=0 ; j<3 ; j++)
1533                         end[j] = check->v.origin[j]
1534                         + 0.5*(check->v.mins[j] + check->v.maxs[j]);
1535                 VectorSubtract (end, start, dir);
1536                 VectorNormalize (dir);
1537                 dist = DotProduct (dir, pr_global_struct->v_forward);
1538                 if (dist < bestdist)
1539                         continue;       // to far to turn
1540                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1541                 if (tr.ent == check)
1542                 {       // can shoot at this one
1543                         bestdist = dist;
1544                         bestent = check;
1545                 }
1546         }
1547
1548         if (bestent)
1549         {
1550                 VectorSubtract (bestent->v.origin, ent->v.origin, dir);
1551                 dist = DotProduct (dir, pr_global_struct->v_forward);
1552                 VectorScale (pr_global_struct->v_forward, dist, end);
1553                 end[2] = dir[2];
1554                 VectorNormalize (end);
1555                 VectorCopy (end, G_VECTOR(OFS_RETURN));
1556         }
1557         else
1558         {
1559                 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1560         }
1561 }
1562
1563 /*
1564 ==============
1565 PF_changeyaw
1566
1567 This was a major timewaster in progs, so it was converted to C
1568 ==============
1569 */
1570 void PF_changeyaw (void)
1571 {
1572         edict_t         *ent;
1573         float           ideal, current, move, speed;
1574
1575         ent = PROG_TO_EDICT(pr_global_struct->self);
1576         current = ANGLEMOD(ent->v.angles[1]);
1577         ideal = ent->v.ideal_yaw;
1578         speed = ent->v.yaw_speed;
1579
1580         if (current == ideal)
1581                 return;
1582         move = ideal - current;
1583         if (ideal > current)
1584         {
1585                 if (move >= 180)
1586                         move = move - 360;
1587         }
1588         else
1589         {
1590                 if (move <= -180)
1591                         move = move + 360;
1592         }
1593         if (move > 0)
1594         {
1595                 if (move > speed)
1596                         move = speed;
1597         }
1598         else
1599         {
1600                 if (move < -speed)
1601                         move = -speed;
1602         }
1603
1604         ent->v.angles[1] = ANGLEMOD (current + move);
1605 }
1606
1607 /*
1608 ==============
1609 PF_changepitch
1610 ==============
1611 */
1612 void PF_changepitch (void)
1613 {
1614         edict_t         *ent;
1615         float           ideal, current, move, speed;
1616         eval_t          *val;
1617
1618         ent = G_EDICT(OFS_PARM0);
1619         current = ANGLEMOD( ent->v.angles[0] );
1620         if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1621                 ideal = val->_float;
1622         else
1623         {
1624                 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1625                 return;
1626         }
1627         if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1628                 speed = val->_float;
1629         else
1630         {
1631                 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1632                 return;
1633         }
1634
1635         if (current == ideal)
1636                 return;
1637         move = ideal - current;
1638         if (ideal > current)
1639         {
1640                 if (move >= 180)
1641                         move = move - 360;
1642         }
1643         else
1644         {
1645                 if (move <= -180)
1646                         move = move + 360;
1647         }
1648         if (move > 0)
1649         {
1650                 if (move > speed)
1651                         move = speed;
1652         }
1653         else
1654         {
1655                 if (move < -speed)
1656                         move = -speed;
1657         }
1658
1659         ent->v.angles[0] = ANGLEMOD (current + move);
1660 }
1661
1662 /*
1663 ===============================================================================
1664
1665 MESSAGE WRITING
1666
1667 ===============================================================================
1668 */
1669
1670 #define MSG_BROADCAST   0               // unreliable to all
1671 #define MSG_ONE                 1               // reliable to one (msg_entity)
1672 #define MSG_ALL                 2               // reliable to all
1673 #define MSG_INIT                3               // write to the init string
1674
1675 sizebuf_t *WriteDest (void)
1676 {
1677         int             entnum;
1678         int             dest;
1679         edict_t *ent;
1680
1681         dest = G_FLOAT(OFS_PARM0);
1682         switch (dest)
1683         {
1684         case MSG_BROADCAST:
1685                 return &sv.datagram;
1686
1687         case MSG_ONE:
1688                 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1689                 entnum = NUM_FOR_EDICT(ent);
1690                 if (entnum < 1 || entnum > svs.maxclients)
1691                         PR_RunError ("WriteDest: not a client");
1692                 return &svs.clients[entnum-1].message;
1693
1694         case MSG_ALL:
1695                 return &sv.reliable_datagram;
1696
1697         case MSG_INIT:
1698                 return &sv.signon;
1699
1700         default:
1701                 PR_RunError ("WriteDest: bad destination");
1702                 break;
1703         }
1704
1705         return NULL;
1706 }
1707
1708 void PF_WriteByte (void)
1709 {
1710         MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1711 }
1712
1713 void PF_WriteChar (void)
1714 {
1715         MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1716 }
1717
1718 void PF_WriteShort (void)
1719 {
1720         MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1721 }
1722
1723 void PF_WriteLong (void)
1724 {
1725         MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1726 }
1727
1728 void PF_WriteAngle (void)
1729 {
1730         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1731 }
1732
1733 void PF_WriteCoord (void)
1734 {
1735         MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1736 }
1737
1738 void PF_WriteString (void)
1739 {
1740         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1741 }
1742
1743
1744 void PF_WriteEntity (void)
1745 {
1746         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1747 }
1748
1749 //=============================================================================
1750
1751 int SV_ModelIndex (char *name);
1752
1753 void PF_makestatic (void)
1754 {
1755         edict_t *ent;
1756         int             i, large;
1757
1758         ent = G_EDICT(OFS_PARM0);
1759
1760         large = false;
1761         if (ent->v.modelindex >= 256 || ent->v.frame >= 256)
1762                 large = true;
1763
1764         if (large)
1765         {
1766                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1767                 MSG_WriteShort (&sv.signon, ent->v.modelindex);
1768                 MSG_WriteShort (&sv.signon, ent->v.frame);
1769         }
1770         else
1771         {
1772                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1773                 MSG_WriteByte (&sv.signon, ent->v.modelindex);
1774                 MSG_WriteByte (&sv.signon, ent->v.frame);
1775         }
1776
1777         MSG_WriteByte (&sv.signon, ent->v.colormap);
1778         MSG_WriteByte (&sv.signon, ent->v.skin);
1779         for (i=0 ; i<3 ; i++)
1780         {
1781                 MSG_WriteDPCoord(&sv.signon, ent->v.origin[i]);
1782                 MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1783         }
1784
1785 // throw the entity away now
1786         ED_Free (ent);
1787 }
1788
1789 //=============================================================================
1790
1791 /*
1792 ==============
1793 PF_setspawnparms
1794 ==============
1795 */
1796 void PF_setspawnparms (void)
1797 {
1798         edict_t *ent;
1799         int             i;
1800         client_t        *client;
1801
1802         ent = G_EDICT(OFS_PARM0);
1803         i = NUM_FOR_EDICT(ent);
1804         if (i < 1 || i > svs.maxclients)
1805                 PR_RunError ("Entity is not a client");
1806
1807         // copy spawn parms out of the client_t
1808         client = svs.clients + (i-1);
1809
1810         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1811                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1812 }
1813
1814 /*
1815 ==============
1816 PF_changelevel
1817 ==============
1818 */
1819 void PF_changelevel (void)
1820 {
1821         char    *s;
1822
1823 // make sure we don't issue two changelevels
1824         if (svs.changelevel_issued)
1825                 return;
1826         svs.changelevel_issued = true;
1827
1828         s = G_STRING(OFS_PARM0);
1829         Cbuf_AddText (va("changelevel %s\n",s));
1830 }
1831
1832 void PF_sin (void)
1833 {
1834         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1835 }
1836
1837 void PF_cos (void)
1838 {
1839         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1840 }
1841
1842 void PF_sqrt (void)
1843 {
1844         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1845 }
1846
1847 /*
1848 =================
1849 PF_RandomVec
1850
1851 Returns a vector of length < 1
1852
1853 randomvec()
1854 =================
1855 */
1856 void PF_randomvec (void)
1857 {
1858         vec3_t          temp;
1859         do
1860         {
1861                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1862                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1863                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1864         }
1865         while (DotProduct(temp, temp) >= 1);
1866         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1867 }
1868
1869 void SV_LightPoint (vec3_t color, vec3_t p);
1870 /*
1871 =================
1872 PF_GetLight
1873
1874 Returns a color vector indicating the lighting at the requested point.
1875
1876 (Internal Operation note: actually measures the light beneath the point, just like
1877                           the model lighting on the client)
1878
1879 getlight(vector)
1880 =================
1881 */
1882 void PF_GetLight (void)
1883 {
1884         vec3_t          color;
1885         vec_t*          p;
1886         p = G_VECTOR(OFS_PARM0);
1887         SV_LightPoint (color, p);
1888         VectorCopy (color, G_VECTOR(OFS_RETURN));
1889 }
1890
1891 #define MAX_QC_CVARS 128
1892 cvar_t qc_cvar[MAX_QC_CVARS];
1893 int currentqc_cvar;
1894
1895 void PF_registercvar (void)
1896 {
1897         char *name, *value;
1898         cvar_t *variable;
1899         name = G_STRING(OFS_PARM0);
1900         value = G_STRING(OFS_PARM1);
1901         G_FLOAT(OFS_RETURN) = 0;
1902 // first check to see if it has already been defined
1903         if (Cvar_FindVar (name))
1904                 return;
1905
1906 // check for overlap with a command
1907         if (Cmd_Exists (name))
1908         {
1909                 Con_Printf ("PF_registercvar: %s is a command\n", name);
1910                 return;
1911         }
1912
1913         if (currentqc_cvar >= MAX_QC_CVARS)
1914                 PR_RunError ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1915
1916 // copy the name and value
1917         variable = &qc_cvar[currentqc_cvar++];
1918         variable->name = Z_Malloc (strlen(name)+1);
1919         strcpy (variable->name, name);
1920         variable->string = Z_Malloc (strlen(value)+1);
1921         strcpy (variable->string, value);
1922         variable->value = atof (value);
1923
1924         Cvar_RegisterVariable(variable);
1925         G_FLOAT(OFS_RETURN) = 1; // success
1926 }
1927
1928 /*
1929 =================
1930 PF_min
1931
1932 returns the minimum of two supplied floats
1933
1934 min(a, b)
1935 =================
1936 */
1937 void PF_min (void)
1938 {
1939         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1940         if (pr_argc == 2)
1941                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1942         else if (pr_argc >= 3)
1943         {
1944                 int i;
1945                 float f = G_FLOAT(OFS_PARM0);
1946                 for (i = 1;i < pr_argc;i++)
1947                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
1948                                 f = G_FLOAT((OFS_PARM0+i*3));
1949                 G_FLOAT(OFS_RETURN) = f;
1950         }
1951         else
1952                 PR_RunError("min: must supply at least 2 floats\n");
1953 }
1954
1955 /*
1956 =================
1957 PF_max
1958
1959 returns the maximum of two supplied floats
1960
1961 max(a, b)
1962 =================
1963 */
1964 void PF_max (void)
1965 {
1966         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1967         if (pr_argc == 2)
1968                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1969         else if (pr_argc >= 3)
1970         {
1971                 int i;
1972                 float f = G_FLOAT(OFS_PARM0);
1973                 for (i = 1;i < pr_argc;i++)
1974                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
1975                                 f = G_FLOAT((OFS_PARM0+i*3));
1976                 G_FLOAT(OFS_RETURN) = f;
1977         }
1978         else
1979                 PR_RunError("max: must supply at least 2 floats\n");
1980 }
1981
1982 /*
1983 =================
1984 PF_bound
1985
1986 returns number bounded by supplied range
1987
1988 min(min, value, max)
1989 =================
1990 */
1991 void PF_bound (void)
1992 {
1993         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
1994 }
1995
1996 /*
1997 =================
1998 PF_pow
1999
2000 returns a raised to power b
2001
2002 pow(a, b)
2003 =================
2004 */
2005 void PF_pow (void)
2006 {
2007         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2008 }
2009
2010 /*
2011 =================
2012 PF_copyentity
2013
2014 copies data from one entity to another
2015
2016 copyentity(src, dst)
2017 =================
2018 */
2019 void PF_copyentity (void)
2020 {
2021         edict_t *in, *out;
2022         in = G_EDICT(OFS_PARM0);
2023         out = G_EDICT(OFS_PARM1);
2024         memcpy(out, in, pr_edict_size);
2025 }
2026
2027 /*
2028 =================
2029 PF_setcolor
2030
2031 sets the color of a client and broadcasts the update to all connected clients
2032
2033 setcolor(clientent, value)
2034 =================
2035 */
2036 void PF_setcolor (void)
2037 {
2038         client_t        *client;
2039         int                     entnum, i;
2040
2041         entnum = G_EDICTNUM(OFS_PARM0);
2042         i = G_FLOAT(OFS_PARM1);
2043
2044         if (entnum < 1 || entnum > svs.maxclients)
2045         {
2046                 Con_Printf ("tried to setcolor a non-client\n");
2047                 return;
2048         }
2049
2050         client = &svs.clients[entnum-1];
2051         client->colors = i;
2052         client->edict->v.team = (i & 15) + 1;
2053
2054         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2055         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2056         MSG_WriteByte (&sv.reliable_datagram, i);
2057 }
2058
2059 /*
2060 =================
2061 PF_effect
2062
2063 effect(origin, modelname, startframe, framecount, framerate)
2064 =================
2065 */
2066 void PF_effect (void)
2067 {
2068         char *s;
2069         s = G_STRING(OFS_PARM1);
2070         if (!s || !s[0])
2071                 PR_RunError("effect: no model specified\n");
2072
2073         SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2074 }
2075
2076 void PF_te_blood (void)
2077 {
2078         if (G_FLOAT(OFS_PARM2) < 1)
2079                 return;
2080         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2081         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2082         // origin
2083         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2084         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2085         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2086         // velocity
2087         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2088         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2089         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2090         // count
2091         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2092 }
2093
2094 void PF_te_bloodshower (void)
2095 {
2096         if (G_FLOAT(OFS_PARM3) < 1)
2097                 return;
2098         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2099         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2100         // min
2101         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2102         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2103         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2104         // max
2105         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2106         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2107         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2108         // speed
2109         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2110         // count
2111         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2112 }
2113
2114 void PF_te_explosionrgb (void)
2115 {
2116         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2117         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2118         // origin
2119         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2120         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2121         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2122         // color
2123         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2124         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2125         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2126 }
2127
2128 void PF_te_particlecube (void)
2129 {
2130         if (G_FLOAT(OFS_PARM3) < 1)
2131                 return;
2132         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2133         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2134         // min
2135         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2136         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2137         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2138         // max
2139         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2140         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2141         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2142         // velocity
2143         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2144         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2145         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2146         // count
2147         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2148         // color
2149         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2150         // gravity true/false
2151         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2152         // randomvel
2153         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2154 }
2155
2156 void PF_te_particlerain (void)
2157 {
2158         if (G_FLOAT(OFS_PARM3) < 1)
2159                 return;
2160         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2161         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2162         // min
2163         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2164         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2165         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2166         // max
2167         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2168         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2169         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2170         // velocity
2171         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2172         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2173         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2174         // count
2175         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2176         // color
2177         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2178 }
2179
2180 void PF_te_particlesnow (void)
2181 {
2182         if (G_FLOAT(OFS_PARM3) < 1)
2183                 return;
2184         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2185         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2186         // min
2187         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2188         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2189         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2190         // max
2191         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2192         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2193         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2194         // velocity
2195         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2196         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2197         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2198         // count
2199         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2200         // color
2201         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2202 }
2203
2204 void PF_te_spark (void)
2205 {
2206         if (G_FLOAT(OFS_PARM2) < 1)
2207                 return;
2208         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2209         MSG_WriteByte(&sv.datagram, TE_SPARK);
2210         // origin
2211         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2212         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2213         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2214         // velocity
2215         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2216         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2217         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2218         // count
2219         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2220 }
2221
2222 void PF_te_gunshotquad (void)
2223 {
2224         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2225         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2226         // origin
2227         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2228         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2229         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2230 }
2231
2232 void PF_te_spikequad (void)
2233 {
2234         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2235         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2236         // origin
2237         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2238         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2239         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2240 }
2241
2242 void PF_te_superspikequad (void)
2243 {
2244         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2245         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2246         // origin
2247         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2248         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2249         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2250 }
2251
2252 void PF_te_explosionquad (void)
2253 {
2254         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2255         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2256         // origin
2257         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2258         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2259         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2260 }
2261
2262 void PF_te_smallflash (void)
2263 {
2264         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2265         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2266         // origin
2267         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2268         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2269         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2270 }
2271
2272 void PF_te_customflash (void)
2273 {
2274         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2275                 return;
2276         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2277         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2278         // origin
2279         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2280         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2281         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2282         // radius
2283         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2284         // lifetime
2285         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2286         // color
2287         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2288         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2289         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2290 }
2291
2292 void PF_te_gunshot (void)
2293 {
2294         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2295         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2296         // origin
2297         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2298         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2299         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2300 }
2301
2302 void PF_te_spike (void)
2303 {
2304         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2305         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2306         // origin
2307         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2308         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2309         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2310 }
2311
2312 void PF_te_superspike (void)
2313 {
2314         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2315         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2316         // origin
2317         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2318         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2319         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2320 }
2321
2322 void PF_te_explosion (void)
2323 {
2324         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2325         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2326         // origin
2327         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2328         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2329         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2330 }
2331
2332 void PF_te_tarexplosion (void)
2333 {
2334         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2335         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2336         // origin
2337         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2338         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2339         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2340 }
2341
2342 void PF_te_wizspike (void)
2343 {
2344         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2345         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2346         // origin
2347         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2348         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2349         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2350 }
2351
2352 void PF_te_knightspike (void)
2353 {
2354         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2355         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2356         // origin
2357         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2358         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2359         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2360 }
2361
2362 void PF_te_lavasplash (void)
2363 {
2364         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2365         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2366         // origin
2367         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2368         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2369         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2370 }
2371
2372 void PF_te_teleport (void)
2373 {
2374         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2375         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2376         // origin
2377         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2378         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2379         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2380 }
2381
2382 void PF_te_explosion2 (void)
2383 {
2384         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2385         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2386         // origin
2387         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2388         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2389         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2390         // color
2391         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2392 }
2393
2394 void PF_te_lightning1 (void)
2395 {
2396         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2398         // owner entity
2399         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2400         // start
2401         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2402         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2403         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2404         // end
2405         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2406         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2407         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2408 }
2409
2410 void PF_te_lightning2 (void)
2411 {
2412         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2413         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2414         // owner entity
2415         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2416         // start
2417         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2418         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2419         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2420         // end
2421         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2422         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2423         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2424 }
2425
2426 void PF_te_lightning3 (void)
2427 {
2428         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2429         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2430         // owner entity
2431         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2432         // start
2433         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2434         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2435         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2436         // end
2437         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2438         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2439         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2440 }
2441
2442 void PF_te_beam (void)
2443 {
2444         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2445         MSG_WriteByte(&sv.datagram, TE_BEAM);
2446         // owner entity
2447         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2448         // start
2449         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2450         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2451         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2452         // end
2453         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2454         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2455         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2456 }
2457
2458 void PF_te_plasmaburn (void)
2459 {
2460         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2461         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2462         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2463         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2464         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2465 }
2466
2467 void PF_Fixme (void)
2468 {
2469         PR_RunError ("unimplemented builtin"); // LordHavoc: was misspelled (bulitin)
2470 }
2471
2472
2473
2474 builtin_t pr_builtin[] =
2475 {
2476 PF_Fixme,
2477 PF_makevectors, // void(entity e)       makevectors             = #1;
2478 PF_setorigin,   // void(entity e, vector o) setorigin   = #2;
2479 PF_setmodel,    // void(entity e, string m) setmodel    = #3;
2480 PF_setsize,     // void(entity e, vector min, vector max) setsize = #4;
2481 PF_Fixme,       // void(entity e, vector min, vector max) setabssize = #5;
2482 PF_break,       // void() break                                         = #6;
2483 PF_random,      // float() random                                               = #7;
2484 PF_sound,       // void(entity e, float chan, string samp) sound = #8;
2485 PF_normalize,   // vector(vector v) normalize                   = #9;
2486 PF_error,       // void(string e) error                         = #10;
2487 PF_objerror,    // void(string e) objerror                              = #11;
2488 PF_vlen,        // float(vector v) vlen                         = #12;
2489 PF_vectoyaw,    // float(vector v) vectoyaw             = #13;
2490 PF_Spawn,       // entity() spawn                                               = #14;
2491 PF_Remove,      // void(entity e) remove                                = #15;
2492 PF_traceline,   // float(vector v1, vector v2, float tryents) traceline = #16;
2493 PF_checkclient, // entity() clientlist                                  = #17;
2494 PF_Find,        // entity(entity start, .string fld, string match) find = #18;
2495 PF_precache_sound,      // void(string s) precache_sound                = #19;
2496 PF_precache_model,      // void(string s) precache_model                = #20;
2497 PF_stuffcmd,    // void(entity client, string s)stuffcmd = #21;
2498 PF_findradius,  // entity(vector org, float rad) findradius = #22;
2499 PF_bprint,      // void(string s) bprint                                = #23;
2500 PF_sprint,      // void(entity client, string s) sprint = #24;
2501 PF_dprint,      // void(string s) dprint                                = #25;
2502 PF_ftos,        // void(string s) ftos                          = #26;
2503 PF_vtos,        // void(string s) vtos                          = #27;
2504 PF_coredump,
2505 PF_traceon,
2506 PF_traceoff,
2507 PF_eprint,      // void(entity e) debug print an entire entity
2508 PF_walkmove, // float(float yaw, float dist) walkmove
2509 PF_Fixme, // float(float yaw, float dist) walkmove
2510 PF_droptofloor,
2511 PF_lightstyle,
2512 PF_rint,
2513 PF_floor,
2514 PF_ceil,
2515 PF_Fixme,
2516 PF_checkbottom,
2517 PF_pointcontents,
2518 PF_Fixme,
2519 PF_fabs,
2520 PF_aim,
2521 PF_cvar,
2522 PF_localcmd,
2523 PF_nextent,
2524 PF_particle,
2525 PF_changeyaw,
2526 PF_Fixme,
2527 PF_vectoangles,
2528
2529 PF_WriteByte,
2530 PF_WriteChar,
2531 PF_WriteShort,
2532 PF_WriteLong,
2533 PF_WriteCoord,
2534 PF_WriteAngle,
2535 PF_WriteString,
2536 PF_WriteEntity,
2537
2538 PF_sin,
2539 PF_cos,
2540 PF_sqrt,
2541 PF_changepitch,
2542 PF_TraceToss,
2543 PF_etos,
2544 PF_Fixme,
2545
2546 SV_MoveToGoal,
2547 PF_precache_file,
2548 PF_makestatic,
2549
2550 PF_changelevel,
2551 PF_Fixme,
2552
2553 PF_cvar_set,
2554 PF_centerprint,
2555
2556 PF_ambientsound,
2557
2558 PF_precache_model,
2559 PF_precache_sound,              // precache_sound2 is different only for qcc
2560 PF_precache_file,
2561
2562 PF_setspawnparms,
2563
2564 PF_Fixme,                               // #79 LordHavoc: dunno who owns 79-89, so these are just padding
2565 PF_Fixme,                               // #80
2566 PF_Fixme,                               // #81
2567 PF_Fixme,                               // #82
2568 PF_Fixme,                               // #83
2569 PF_Fixme,                               // #84
2570 PF_Fixme,                               // #85
2571 PF_Fixme,                               // #86
2572 PF_Fixme,                               // #87
2573 PF_Fixme,                               // #88
2574 PF_Fixme,                               // #89
2575
2576 PF_tracebox,                    // #90 LordHavoc builtin range (9x)
2577 PF_randomvec,                   // #91
2578 PF_GetLight,                    // #92
2579 PF_registercvar,                // #93
2580 PF_min,                                 // #94
2581 PF_max,                                 // #95
2582 PF_bound,                               // #96
2583 PF_pow,                                 // #97
2584 PF_FindFloat,                   // #98
2585 PF_checkextension,              // #99
2586 #define a PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme,
2587 #define aa a a a a a a a a a a
2588 aa // #200
2589 aa // #300
2590 aa // #400
2591 PF_copyentity,                  // #400 LordHavoc: builtin range (4xx)
2592 PF_setcolor,                    // #401
2593 PF_findchain,                   // #402
2594 PF_findchainfloat,              // #403
2595 PF_effect,                              // #404
2596 PF_te_blood,                    // #405
2597 PF_te_bloodshower,              // #406
2598 PF_te_explosionrgb,             // #407
2599 PF_te_particlecube,             // #408
2600 PF_te_particlerain,             // #409
2601 PF_te_particlesnow,             // #410
2602 PF_te_spark,                    // #411
2603 PF_te_gunshotquad,              // #412
2604 PF_te_spikequad,                // #413
2605 PF_te_superspikequad,   // #414
2606 PF_te_explosionquad,    // #415
2607 PF_te_smallflash,               // #416
2608 PF_te_customflash,              // #417
2609 PF_te_gunshot,                  // #418
2610 PF_te_spike,                    // #419
2611 PF_te_superspike,               // #420
2612 PF_te_explosion,                // #421
2613 PF_te_tarexplosion,             // #422
2614 PF_te_wizspike,                 // #423
2615 PF_te_knightspike,              // #424
2616 PF_te_lavasplash,               // #425
2617 PF_te_teleport,                 // #426
2618 PF_te_explosion2,               // #427
2619 PF_te_lightning1,               // #428
2620 PF_te_lightning2,               // #429
2621 PF_te_lightning3,               // #430
2622 PF_te_beam,                             // #431
2623 PF_vectorvectors,               // #432
2624 PF_te_plasmaburn,               // #433
2625 };
2626
2627 builtin_t *pr_builtins = pr_builtin;
2628 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
2629