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