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