]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
disabled memory clumping, which surprisingly improves memory use, rather than hinders...
[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[256];
41
42         out[0] = 0;
43         for (i=first ; i<pr_argc ; i++)
44         {
45                 strcat (out, G_STRING((OFS_PARM0+i*3)));
46         }
47         return out;
48 }
49
50 char *ENGINE_EXTENSIONS = "\
51 DP_ENT_ALPHA \
52 DP_ENT_COLORMOD \
53 DP_ENT_DELTACOMPRESS \
54 DP_ENT_GLOW \
55 DP_ENT_SCALE \
56 DP_ENT_VIEWMODEL \
57 DP_GFX_FOG \
58 DP_HALFLIFE_MAP \
59 DP_INPUTBUTTONS \
60 DP_MONSTERWALK \
61 DP_MOVETYPEFOLLOW \
62 DP_QC_CHANGEPITCH \
63 DP_QC_COPYENTITY \
64 DP_QC_ETOS \
65 DP_QC_FINDCHAIN \
66 DP_QC_FINDCHAINFLOAT \
67 DP_QC_FINDFLOAT \
68 DP_QC_GETLIGHT \
69 DP_QC_MINMAXBOUND \
70 DP_QC_RANDOMVEC \
71 DP_QC_SINCOSSQRTPOW \
72 DP_QC_TRACEBOX \
73 DP_QC_TRACETOSS \
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_SETCOLOR \
83 DP_TE_BLOOD \
84 DP_TE_BLOODSHOWER \
85 DP_TE_EXPLOSIONRGB \
86 DP_TE_PARTICLECUBE \
87 DP_TE_PARTICLERAIN \
88 DP_TE_PARTICLESNOW \
89 DP_TE_SPARK \
90 NEH_CMD_PLAY2 \
91 TW_SV_STEPCONTROL \
92 ";
93
94 qboolean checkextension(char *name)
95 {
96         int len;
97         char *e, *start;
98         len = strlen(name);
99         for (e = ENGINE_EXTENSIONS;*e;e++)
100         {
101                 while (*e == ' ')
102                         e++;
103                 if (!*e)
104                         break;
105                 start = e;
106                 while (*e && *e != ' ')
107                         e++;
108                 if (e - start == len)
109                         if (!strncasecmp(start, name, len))
110                                 return true;
111         }
112         return false;
113 }
114
115 /*
116 =================
117 PF_checkextension
118
119 returns true if the extension is supported by the server
120
121 checkextension(extensionname)
122 =================
123 */
124 void PF_checkextension (void)
125 {
126         G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
127 }
128
129 /*
130 =================
131 PF_error
132
133 This is a TERMINAL error, which will kill off the entire server.
134 Dumps self.
135
136 error(value)
137 =================
138 */
139 void PF_error (void)
140 {
141         char    *s;
142         edict_t *ed;
143         
144         s = PF_VarString(0);
145         Con_Printf ("======SERVER ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s);
146         ed = PROG_TO_EDICT(pr_global_struct->self);
147         ED_Print (ed);
148
149         Host_Error ("Program error");
150 }
151
152 /*
153 =================
154 PF_objerror
155
156 Dumps out self, then an error message.  The program is aborted and self is
157 removed, but the level can continue.
158
159 objerror(value)
160 =================
161 */
162 void PF_objerror (void)
163 {
164         char    *s;
165         edict_t *ed;
166         
167         s = PF_VarString(0);
168         Con_Printf ("======OBJECT ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s);
169         ed = PROG_TO_EDICT(pr_global_struct->self);
170         ED_Print (ed);
171         ED_Free (ed);
172 }
173
174
175 /*
176 ==============
177 PF_makevectors
178
179 Writes new values for v_forward, v_up, and v_right based on angles
180 makevectors(vector)
181 ==============
182 */
183 void PF_makevectors (void)
184 {
185         AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
186 }
187
188 /*
189 ==============
190 PF_vectorvectors
191
192 Writes new values for v_forward, v_up, and v_right based on the given forward vector
193 vectorvectors(vector, vector)
194 ==============
195 */
196 void PF_vectorvectors (void)
197 {
198         VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
199         VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
200 }
201
202 /*
203 =================
204 PF_setorigin
205
206 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.
207
208 setorigin (entity, origin)
209 =================
210 */
211 void PF_setorigin (void)
212 {
213         edict_t *e;
214         float   *org;
215         
216         e = G_EDICT(OFS_PARM0);
217         org = G_VECTOR(OFS_PARM1);
218         VectorCopy (org, e->v.origin);
219         SV_LinkEdict (e, false);
220 }
221
222
223 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
224 {
225         int             i;
226         
227         for (i=0 ; i<3 ; i++)
228                 if (min[i] > max[i])
229                         PR_RunError ("backwards mins/maxs");
230
231 // set derived values
232         VectorCopy (min, e->v.mins);
233         VectorCopy (max, e->v.maxs);
234         VectorSubtract (max, min, e->v.size);
235
236         SV_LinkEdict (e, false);
237 }
238
239 /*
240 =================
241 PF_setsize
242
243 the size box is rotated by the current angle
244 LordHavoc: no it isn't...
245
246 setsize (entity, minvector, maxvector)
247 =================
248 */
249 void PF_setsize (void)
250 {
251         edict_t *e;
252         float   *min, *max;
253         
254         e = G_EDICT(OFS_PARM0);
255         min = G_VECTOR(OFS_PARM1);
256         max = G_VECTOR(OFS_PARM2);
257         SetMinMaxSize (e, min, max, false);
258 }
259
260
261 /*
262 =================
263 PF_setmodel
264
265 setmodel(entity, model)
266 =================
267 */
268 void PF_setmodel (void)
269 {
270         edict_t *e;
271         char    *m, **check;
272         model_t *mod;
273         int             i;
274
275         e = G_EDICT(OFS_PARM0);
276         m = G_STRING(OFS_PARM1);
277
278 // check to see if model was properly precached
279         for (i=0, check = sv.model_precache ; *check ; i++, check++)
280                 if (!strcmp(*check, m))
281                         break;
282
283         if (!*check)
284                 PR_RunError ("no precache: %s\n", m);
285
286
287         e->v.model = m - pr_strings;
288         e->v.modelindex = i;
289
290         mod = sv.models[ (int)e->v.modelindex];
291
292         if (mod)
293                 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
294         else
295                 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
296 }
297
298 /*
299 =================
300 PF_bprint
301
302 broadcast print to everyone on server
303
304 bprint(value)
305 =================
306 */
307 void PF_bprint (void)
308 {
309         char            *s;
310
311         s = PF_VarString(0);
312         SV_BroadcastPrintf ("%s", s);
313 }
314
315 /*
316 =================
317 PF_sprint
318
319 single print to a specific client
320
321 sprint(clientent, value)
322 =================
323 */
324 void PF_sprint (void)
325 {
326         char            *s;
327         client_t        *client;
328         int                     entnum;
329         
330         entnum = G_EDICTNUM(OFS_PARM0);
331         s = PF_VarString(1);
332         
333         if (entnum < 1 || entnum > svs.maxclients)
334         {
335                 Con_Printf ("tried to sprint to a non-client\n");
336                 return;
337         }
338                 
339         client = &svs.clients[entnum-1];
340                 
341         MSG_WriteChar (&client->message,svc_print);
342         MSG_WriteString (&client->message, s );
343 }
344
345
346 /*
347 =================
348 PF_centerprint
349
350 single print to a specific client
351
352 centerprint(clientent, value)
353 =================
354 */
355 void PF_centerprint (void)
356 {
357         char            *s;
358         client_t        *client;
359         int                     entnum;
360         
361         entnum = G_EDICTNUM(OFS_PARM0);
362         s = PF_VarString(1);
363         
364         if (entnum < 1 || entnum > svs.maxclients)
365         {
366                 Con_Printf ("tried to sprint to a non-client\n");
367                 return;
368         }
369                 
370         client = &svs.clients[entnum-1];
371                 
372         MSG_WriteChar (&client->message,svc_centerprint);
373         MSG_WriteString (&client->message, s );
374 }
375
376
377 /*
378 =================
379 PF_normalize
380
381 vector normalize(vector)
382 =================
383 */
384 void PF_normalize (void)
385 {
386         float   *value1;
387         vec3_t  newvalue;
388         float   new;
389         
390         value1 = G_VECTOR(OFS_PARM0);
391
392         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
393         new = sqrt(new);
394         
395         if (new == 0)
396                 newvalue[0] = newvalue[1] = newvalue[2] = 0;
397         else
398         {
399                 new = 1/new;
400                 newvalue[0] = value1[0] * new;
401                 newvalue[1] = value1[1] * new;
402                 newvalue[2] = value1[2] * new;
403         }
404         
405         VectorCopy (newvalue, G_VECTOR(OFS_RETURN));    
406 }
407
408 /*
409 =================
410 PF_vlen
411
412 scalar vlen(vector)
413 =================
414 */
415 void PF_vlen (void)
416 {
417         float   *value1;
418         float   new;
419
420         value1 = G_VECTOR(OFS_PARM0);
421
422         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
423         new = sqrt(new);
424         
425         G_FLOAT(OFS_RETURN) = new;
426 }
427
428 /*
429 =================
430 PF_vectoyaw
431
432 float vectoyaw(vector)
433 =================
434 */
435 void PF_vectoyaw (void)
436 {
437         float   *value1;
438         float   yaw;
439         
440         value1 = G_VECTOR(OFS_PARM0);
441
442         if (value1[1] == 0 && value1[0] == 0)
443                 yaw = 0;
444         else
445         {
446                 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
447                 if (yaw < 0)
448                         yaw += 360;
449         }
450
451         G_FLOAT(OFS_RETURN) = yaw;
452 }
453
454
455 /*
456 =================
457 PF_vectoangles
458
459 vector vectoangles(vector)
460 =================
461 */
462 void PF_vectoangles (void)
463 {
464         float   *value1;
465         float   forward;
466         float   yaw, pitch;
467         
468         value1 = G_VECTOR(OFS_PARM0);
469
470         if (value1[1] == 0 && value1[0] == 0)
471         {
472                 yaw = 0;
473                 if (value1[2] > 0)
474                         pitch = 90;
475                 else
476                         pitch = 270;
477         }
478         else
479         {
480                 // LordHavoc: optimized a bit
481                 if (value1[0])
482                 {
483                         yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
484                         if (yaw < 0)
485                                 yaw += 360;
486                 }
487                 else if (value1[1] > 0)
488                         yaw = 90;
489                 else
490                         yaw = 270;
491
492                 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
493                 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
494                 if (pitch < 0)
495                         pitch += 360;
496         }
497
498         G_FLOAT(OFS_RETURN+0) = pitch;
499         G_FLOAT(OFS_RETURN+1) = yaw;
500         G_FLOAT(OFS_RETURN+2) = 0;
501 }
502
503 /*
504 =================
505 PF_Random
506
507 Returns a number from 0<= num < 1
508
509 random()
510 =================
511 */
512 void PF_random (void)
513 {
514         float           num;
515                 
516         num = (rand ()&0x7fff) / ((float)0x7fff);
517         
518         G_FLOAT(OFS_RETURN) = num;
519 }
520
521 /*
522 =================
523 PF_particle
524
525 particle(origin, color, count)
526 =================
527 */
528 void PF_particle (void)
529 {
530         float           *org, *dir;
531         float           color;
532         float           count;
533                         
534         org = G_VECTOR(OFS_PARM0);
535         dir = G_VECTOR(OFS_PARM1);
536         color = G_FLOAT(OFS_PARM2);
537         count = G_FLOAT(OFS_PARM3);
538         SV_StartParticle (org, dir, color, count);
539 }
540
541
542 /*
543 =================
544 PF_ambientsound
545
546 =================
547 */
548 void PF_ambientsound (void)
549 {
550         char            **check;
551         char            *samp;
552         float           *pos;
553         float           vol, attenuation;
554         int                     i, soundnum, large;
555
556         pos = G_VECTOR (OFS_PARM0);                     
557         samp = G_STRING(OFS_PARM1);
558         vol = G_FLOAT(OFS_PARM2);
559         attenuation = G_FLOAT(OFS_PARM3);
560         
561 // check to see if samp was properly precached
562         for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
563                 if (!strcmp(*check,samp))
564                         break;
565
566         if (!*check)
567         {
568                 Con_Printf ("no precache: %s\n", samp);
569                 return;
570         }
571
572         large = false;
573         if (soundnum >= 256)
574                 large = true;
575
576         // add an svc_spawnambient command to the level signon packet
577
578         if (large)
579                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
580         else
581                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
582
583         for (i=0 ; i<3 ; i++)
584                 MSG_WriteDPCoord(&sv.signon, pos[i]);
585
586         if (large)
587                 MSG_WriteShort (&sv.signon, soundnum);
588         else
589                 MSG_WriteByte (&sv.signon, soundnum);
590
591         MSG_WriteByte (&sv.signon, vol*255);
592         MSG_WriteByte (&sv.signon, attenuation*64);
593
594 }
595
596 /*
597 =================
598 PF_sound
599
600 Each entity can have eight independant sound sources, like voice,
601 weapon, feet, etc.
602
603 Channel 0 is an auto-allocate channel, the others override anything
604 already running on that entity/channel pair.
605
606 An attenuation of 0 will play full volume everywhere in the level.
607 Larger attenuations will drop off.
608
609 =================
610 */
611 void PF_sound (void)
612 {
613         char            *sample;
614         int                     channel;
615         edict_t         *entity;
616         int             volume;
617         float attenuation;
618                 
619         entity = G_EDICT(OFS_PARM0);
620         channel = G_FLOAT(OFS_PARM1);
621         sample = G_STRING(OFS_PARM2);
622         volume = G_FLOAT(OFS_PARM3) * 255;
623         attenuation = G_FLOAT(OFS_PARM4);
624         
625         if (volume < 0 || volume > 255)
626                 Host_Error ("SV_StartSound: volume = %i", volume);
627
628         if (attenuation < 0 || attenuation > 4)
629                 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
630
631         if (channel < 0 || channel > 7)
632                 Host_Error ("SV_StartSound: channel = %i", channel);
633
634         SV_StartSound (entity, channel, sample, volume, attenuation);
635 }
636
637 /*
638 =================
639 PF_break
640
641 break()
642 =================
643 */
644 void PF_break (void)
645 {
646         PR_RunError ("break statement");
647 }
648
649 /*
650 =================
651 PF_traceline
652
653 Used for use tracing and shot targeting
654 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
655 if the tryents flag is set.
656
657 traceline (vector1, vector2, tryents)
658 =================
659 */
660 void PF_traceline (void)
661 {
662         float   *v1, *v2;
663         trace_t trace;
664         int             nomonsters;
665         edict_t *ent;
666
667         v1 = G_VECTOR(OFS_PARM0);
668         v2 = G_VECTOR(OFS_PARM1);
669         nomonsters = G_FLOAT(OFS_PARM2);
670         ent = G_EDICT(OFS_PARM3);
671
672         trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
673
674         pr_global_struct->trace_allsolid = trace.allsolid;
675         pr_global_struct->trace_startsolid = trace.startsolid;
676         pr_global_struct->trace_fraction = trace.fraction;
677         pr_global_struct->trace_inwater = trace.inwater;
678         pr_global_struct->trace_inopen = trace.inopen;
679         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
680         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
681         pr_global_struct->trace_plane_dist =  trace.plane.dist;
682         if (trace.ent)
683                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
684         else
685                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
686         // FIXME: add trace_endcontents
687 }
688
689
690 /*
691 =================
692 PF_tracebox
693
694 Used for use tracing and shot targeting
695 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
696 if the tryents flag is set.
697
698 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
699 =================
700 */
701 // LordHavoc: added this for my own use, VERY useful, similar to traceline
702 void PF_tracebox (void)
703 {
704         float   *v1, *v2, *m1, *m2;
705         trace_t trace;
706         int             nomonsters;
707         edict_t *ent;
708
709         v1 = G_VECTOR(OFS_PARM0);
710         m1 = G_VECTOR(OFS_PARM1);
711         m2 = G_VECTOR(OFS_PARM2);
712         v2 = G_VECTOR(OFS_PARM3);
713         nomonsters = G_FLOAT(OFS_PARM4);
714         ent = G_EDICT(OFS_PARM5);
715
716         trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
717
718         pr_global_struct->trace_allsolid = trace.allsolid;
719         pr_global_struct->trace_startsolid = trace.startsolid;
720         pr_global_struct->trace_fraction = trace.fraction;
721         pr_global_struct->trace_inwater = trace.inwater;
722         pr_global_struct->trace_inopen = trace.inopen;
723         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
724         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
725         pr_global_struct->trace_plane_dist =  trace.plane.dist; 
726         if (trace.ent)
727                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
728         else
729                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
730 }
731
732 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
733 void PF_TraceToss (void)
734 {
735         trace_t trace;
736         edict_t *ent;
737         edict_t *ignore;
738
739         ent = G_EDICT(OFS_PARM0);
740         ignore = G_EDICT(OFS_PARM1);
741
742         trace = SV_Trace_Toss (ent, ignore);
743
744         pr_global_struct->trace_allsolid = trace.allsolid;
745         pr_global_struct->trace_startsolid = trace.startsolid;
746         pr_global_struct->trace_fraction = trace.fraction;
747         pr_global_struct->trace_inwater = trace.inwater;
748         pr_global_struct->trace_inopen = trace.inopen;
749         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
750         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
751         pr_global_struct->trace_plane_dist =  trace.plane.dist; 
752         if (trace.ent)
753                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
754         else
755                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
756 }
757
758
759 /*
760 =================
761 PF_checkpos
762
763 Returns true if the given entity can move to the given position from it's
764 current position by walking or rolling.
765 FIXME: make work...
766 scalar checkpos (entity, vector)
767 =================
768 */
769 void PF_checkpos (void)
770 {
771 }
772
773 //============================================================================
774
775 qbyte checkpvs[MAX_MAP_LEAFS/8];
776
777 int PF_newcheckclient (int check)
778 {
779         int             i;
780         qbyte   *pvs;
781         edict_t *ent;
782         mleaf_t *leaf;
783         vec3_t  org;
784
785 // cycle to the next one
786
787         if (check < 1)
788                 check = 1;
789         if (check > svs.maxclients)
790                 check = svs.maxclients;
791
792         if (check == svs.maxclients)
793                 i = 1;
794         else
795                 i = check + 1;
796
797         for ( ;  ; i++)
798         {
799                 if (i == svs.maxclients+1)
800                         i = 1;
801
802                 ent = EDICT_NUM(i);
803
804                 if (i == check)
805                         break;  // didn't find anything else
806
807                 if (ent->free)
808                         continue;
809                 if (ent->v.health <= 0)
810                         continue;
811                 if ((int)ent->v.flags & FL_NOTARGET)
812                         continue;
813
814         // anything that is a client, or has a client as an enemy
815                 break;
816         }
817
818 // get the PVS for the entity
819         VectorAdd (ent->v.origin, ent->v.view_ofs, org);
820         leaf = Mod_PointInLeaf (org, sv.worldmodel);
821         pvs = Mod_LeafPVS (leaf, sv.worldmodel);
822         memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
823
824         return i;
825 }
826
827 /*
828 =================
829 PF_checkclient
830
831 Returns a client (or object that has a client enemy) that would be a
832 valid target.
833
834 If there is more than one valid option, they are cycled each frame
835
836 If (self.origin + self.viewofs) is not in the PVS of the current target,
837 it is not returned at all.
838
839 name checkclient ()
840 =================
841 */
842 int c_invis, c_notvis;
843 void PF_checkclient (void)
844 {
845         edict_t *ent, *self;
846         mleaf_t *leaf;
847         int             l;
848         vec3_t  view;
849         
850 // find a new check if on a new frame
851         if (sv.time - sv.lastchecktime >= 0.1)
852         {
853                 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
854                 sv.lastchecktime = sv.time;
855         }
856
857 // return check if it might be visible  
858         ent = EDICT_NUM(sv.lastcheck);
859         if (ent->free || ent->v.health <= 0)
860         {
861                 RETURN_EDICT(sv.edicts);
862                 return;
863         }
864
865 // if current entity can't possibly see the check entity, return 0
866         self = PROG_TO_EDICT(pr_global_struct->self);
867         VectorAdd (self->v.origin, self->v.view_ofs, view);
868         leaf = Mod_PointInLeaf (view, sv.worldmodel);
869         l = (leaf - sv.worldmodel->leafs) - 1;
870         if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
871         {
872 c_notvis++;
873                 RETURN_EDICT(sv.edicts);
874                 return;
875         }
876
877 // might be able to see it
878 c_invis++;
879         RETURN_EDICT(ent);
880 }
881
882 //============================================================================
883
884
885 /*
886 =================
887 PF_stuffcmd
888
889 Sends text over to the client's execution buffer
890
891 stuffcmd (clientent, value)
892 =================
893 */
894 void PF_stuffcmd (void)
895 {
896         int             entnum;
897         char    *str;
898         client_t        *old;
899         
900         entnum = G_EDICTNUM(OFS_PARM0);
901         if (entnum < 1 || entnum > svs.maxclients)
902                 PR_RunError ("Parm 0 not a client");
903         str = G_STRING(OFS_PARM1);      
904         
905         old = host_client;
906         host_client = &svs.clients[entnum-1];
907         Host_ClientCommands ("%s", str);
908         host_client = old;
909 }
910
911 /*
912 =================
913 PF_localcmd
914
915 Sends text over to the client's execution buffer
916
917 localcmd (string)
918 =================
919 */
920 void PF_localcmd (void)
921 {
922         char    *str;
923
924         str = G_STRING(OFS_PARM0);      
925         Cbuf_AddText (str);
926 }
927
928 /*
929 =================
930 PF_cvar
931
932 float cvar (string)
933 =================
934 */
935 void PF_cvar (void)
936 {
937         char    *str;
938         
939         str = G_STRING(OFS_PARM0);
940         
941         G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
942 }
943
944 /*
945 =================
946 PF_cvar_set
947
948 float cvar (string)
949 =================
950 */
951 void PF_cvar_set (void)
952 {
953         char    *var, *val;
954         
955         var = G_STRING(OFS_PARM0);
956         val = G_STRING(OFS_PARM1);
957         
958         Cvar_Set (var, val);
959 }
960
961 /*
962 =================
963 PF_findradius
964
965 Returns a chain of entities that have origins within a spherical area
966
967 findradius (origin, radius)
968 =================
969 */
970 void PF_findradius (void)
971 {
972         edict_t *ent, *chain;
973         float radius;
974         float radius2;
975         float *org;
976         float eorg[3];
977         int i;
978
979         chain = (edict_t *)sv.edicts;
980         
981         org = G_VECTOR(OFS_PARM0);
982         radius = G_FLOAT(OFS_PARM1);
983         radius2 = radius * radius;
984
985         ent = NEXT_EDICT(sv.edicts);
986         for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
987         {
988                 if (ent->free)
989                         continue;
990                 if (ent->v.solid == SOLID_NOT)
991                         continue;
992
993                 // LordHavoc: compare against bounding box rather than center,
994                 // and use DotProduct instead of Length, major speedup
995                 eorg[0] = (org[0] - ent->v.origin[0]) - bound(ent->v.mins[0], (org[0] - ent->v.origin[0]), ent->v.maxs[0]);
996                 eorg[1] = (org[1] - ent->v.origin[1]) - bound(ent->v.mins[1], (org[1] - ent->v.origin[1]), ent->v.maxs[1]);
997                 eorg[2] = (org[2] - ent->v.origin[2]) - bound(ent->v.mins[2], (org[2] - ent->v.origin[2]), ent->v.maxs[2]);
998                 if (DotProduct(eorg, eorg) > radius2)
999                         continue;
1000                         
1001                 ent->v.chain = EDICT_TO_PROG(chain);
1002                 chain = ent;
1003         }
1004
1005         RETURN_EDICT(chain);
1006 }
1007
1008
1009 /*
1010 =========
1011 PF_dprint
1012 =========
1013 */
1014 void PF_dprint (void)
1015 {
1016         Con_DPrintf ("%s",PF_VarString(0));
1017 }
1018
1019 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1020 #define STRINGTEMP_BUFFERS 16
1021 #define STRINGTEMP_LENGTH 128
1022 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1023 static int pr_string_tempindex = 0;
1024
1025 static char *PR_GetTempString(void)
1026 {
1027         char *s;
1028         s = pr_string_temp[pr_string_tempindex];
1029         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1030         return s;
1031 }
1032
1033 void PF_ftos (void)
1034 {
1035         float v;
1036         char *s;
1037         v = G_FLOAT(OFS_PARM0);
1038
1039         s = PR_GetTempString();
1040         // LordHavoc: ftos improvement
1041         sprintf (s, "%g", v);
1042         G_INT(OFS_RETURN) = s - pr_strings;
1043 }
1044
1045 void PF_fabs (void)
1046 {
1047         float   v;
1048         v = G_FLOAT(OFS_PARM0);
1049         G_FLOAT(OFS_RETURN) = fabs(v);
1050 }
1051
1052 void PF_vtos (void)
1053 {
1054         char *s;
1055         s = PR_GetTempString();
1056         sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1057         G_INT(OFS_RETURN) = s - pr_strings;
1058 }
1059
1060 void PF_etos (void)
1061 {
1062         char *s;
1063         s = PR_GetTempString();
1064         sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1065         G_INT(OFS_RETURN) = s - pr_strings;
1066 }
1067
1068 void PF_Spawn (void)
1069 {
1070         edict_t *ed;
1071         ed = ED_Alloc();
1072         RETURN_EDICT(ed);
1073 }
1074
1075 void PF_Remove (void)
1076 {
1077         edict_t *ed;
1078
1079         ed = G_EDICT(OFS_PARM0);
1080         if (ed == sv.edicts)
1081                 PR_RunError("remove: tried to remove world\n");
1082         if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1083                 PR_RunError("remove: tried to remove a client\n");
1084         ED_Free (ed);
1085 }
1086
1087
1088 // entity (entity start, .string field, string match) find = #5;
1089 void PF_Find (void)
1090 {
1091         int             e;
1092         int             f;
1093         char    *s, *t;
1094         edict_t *ed;
1095
1096         e = G_EDICTNUM(OFS_PARM0);
1097         f = G_INT(OFS_PARM1);
1098         s = G_STRING(OFS_PARM2);
1099         if (!s || !s[0])
1100         {
1101                 RETURN_EDICT(sv.edicts);
1102                 return;
1103         }
1104
1105         for (e++ ; e < sv.num_edicts ; e++)
1106         {
1107                 ed = EDICT_NUM(e);
1108                 if (ed->free)
1109                         continue;
1110                 t = E_STRING(ed,f);
1111                 if (!t)
1112                         continue;
1113                 if (!strcmp(t,s))
1114                 {
1115                         RETURN_EDICT(ed);
1116                         return;
1117                 }
1118         }
1119
1120         RETURN_EDICT(sv.edicts);
1121 }
1122
1123 // LordHavoc: added this for searching float, int, and entity reference fields
1124 void PF_FindFloat (void)
1125 {
1126         int             e;      
1127         int             f;
1128         float   s;
1129         edict_t *ed;
1130
1131         e = G_EDICTNUM(OFS_PARM0);
1132         f = G_INT(OFS_PARM1);
1133         s = G_FLOAT(OFS_PARM2);
1134                 
1135         for (e++ ; e < sv.num_edicts ; e++)
1136         {
1137                 ed = EDICT_NUM(e);
1138                 if (ed->free)
1139                         continue;
1140                 if (E_FLOAT(ed,f) == s)
1141                 {
1142                         RETURN_EDICT(ed);
1143                         return;
1144                 }
1145         }
1146
1147         RETURN_EDICT(sv.edicts);
1148 }
1149
1150 // chained search for strings in entity fields
1151 // entity(.string field, string match) findchain = #402;
1152 void PF_findchain (void)
1153 {
1154         int             i;      
1155         int             f;
1156         char    *s, *t;
1157         edict_t *ent, *chain;
1158
1159         chain = (edict_t *)sv.edicts;
1160
1161         f = G_INT(OFS_PARM0);
1162         s = G_STRING(OFS_PARM1);
1163         if (!s || !s[0])
1164         {
1165                 RETURN_EDICT(sv.edicts);
1166                 return;
1167         }
1168                 
1169         ent = NEXT_EDICT(sv.edicts);
1170         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1171         {
1172                 if (ent->free)
1173                         continue;
1174                 t = E_STRING(ent,f);
1175                 if (!t)
1176                         continue;
1177                 if (strcmp(t,s))
1178                         continue;
1179
1180                 ent->v.chain = EDICT_TO_PROG(chain);
1181                 chain = ent;
1182         }
1183
1184         RETURN_EDICT(chain);
1185 }
1186
1187 // LordHavoc: chained search for float, int, and entity reference fields
1188 // entity(.string field, float match) findchainfloat = #403;
1189 void PF_findchainfloat (void)
1190 {
1191         int             i;      
1192         int             f;
1193         float   s;
1194         edict_t *ent, *chain;
1195
1196         chain = (edict_t *)sv.edicts;
1197
1198         f = G_INT(OFS_PARM0);
1199         s = G_FLOAT(OFS_PARM1);
1200                 
1201         ent = NEXT_EDICT(sv.edicts);
1202         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1203         {
1204                 if (ent->free)
1205                         continue;
1206                 if (E_FLOAT(ent,f) != s)
1207                         continue;
1208
1209                 ent->v.chain = EDICT_TO_PROG(chain);
1210                 chain = ent;
1211         }
1212
1213         RETURN_EDICT(chain);
1214 }
1215
1216 void PR_CheckEmptyString (char *s)
1217 {
1218         if (s[0] <= ' ')
1219                 PR_RunError ("Bad string");
1220 }
1221
1222 void PF_precache_file (void)
1223 {       // precache_file is only used to copy files with qcc, it does nothing
1224         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1225 }
1226
1227 void PF_precache_sound (void)
1228 {
1229         char    *s;
1230         int             i;
1231
1232         if (sv.state != ss_loading)
1233                 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1234
1235         s = G_STRING(OFS_PARM0);
1236         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1237         PR_CheckEmptyString (s);
1238         
1239         for (i=0 ; i<MAX_SOUNDS ; i++)
1240         {
1241                 if (!sv.sound_precache[i])
1242                 {
1243                         sv.sound_precache[i] = s;
1244                         return;
1245                 }
1246                 if (!strcmp(sv.sound_precache[i], s))
1247                         return;
1248         }
1249         PR_RunError ("PF_precache_sound: overflow");
1250 }
1251
1252 void PF_precache_model (void)
1253 {
1254         char    *s;
1255         int             i;
1256         
1257         if (sv.state != ss_loading)
1258                 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1259
1260         s = G_STRING(OFS_PARM0);
1261         if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1262                 return;
1263         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1264         PR_CheckEmptyString (s);
1265
1266         for (i=0 ; i<MAX_MODELS ; i++)
1267         {
1268                 if (!sv.model_precache[i])
1269                 {
1270                         sv.model_precache[i] = s;
1271                         sv.models[i] = Mod_ForName (s, true, false, false);
1272                         return;
1273                 }
1274                 if (!strcmp(sv.model_precache[i], s))
1275                         return;
1276         }
1277         PR_RunError ("PF_precache_model: overflow");
1278 }
1279
1280
1281 void PF_coredump (void)
1282 {
1283         ED_PrintEdicts ();
1284 }
1285
1286 void PF_traceon (void)
1287 {
1288         pr_trace = true;
1289 }
1290
1291 void PF_traceoff (void)
1292 {
1293         pr_trace = false;
1294 }
1295
1296 void PF_eprint (void)
1297 {
1298         ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1299 }
1300
1301 /*
1302 ===============
1303 PF_walkmove
1304
1305 float(float yaw, float dist) walkmove
1306 ===============
1307 */
1308 void PF_walkmove (void)
1309 {
1310         edict_t *ent;
1311         float   yaw, dist;
1312         vec3_t  move;
1313         dfunction_t     *oldf;
1314         int     oldself;
1315         
1316         ent = PROG_TO_EDICT(pr_global_struct->self);
1317         yaw = G_FLOAT(OFS_PARM0);
1318         dist = G_FLOAT(OFS_PARM1);
1319         
1320         if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1321         {
1322                 G_FLOAT(OFS_RETURN) = 0;
1323                 return;
1324         }
1325
1326         yaw = yaw*M_PI*2 / 360;
1327         
1328         move[0] = cos(yaw)*dist;
1329         move[1] = sin(yaw)*dist;
1330         move[2] = 0;
1331
1332 // save program state, because SV_movestep may call other progs
1333         oldf = pr_xfunction;
1334         oldself = pr_global_struct->self;
1335         
1336         G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1337         
1338         
1339 // restore program state
1340         pr_xfunction = oldf;
1341         pr_global_struct->self = oldself;
1342 }
1343
1344 /*
1345 ===============
1346 PF_droptofloor
1347
1348 void() droptofloor
1349 ===============
1350 */
1351 void PF_droptofloor (void)
1352 {
1353         edict_t         *ent;
1354         vec3_t          end;
1355         trace_t         trace;
1356
1357         ent = PROG_TO_EDICT(pr_global_struct->self);
1358
1359         VectorCopy (ent->v.origin, end);
1360         end[2] -= 256;
1361
1362         trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
1363
1364         if (trace.fraction == 1 || trace.allsolid)
1365                 G_FLOAT(OFS_RETURN) = 0;
1366         else
1367         {
1368                 VectorCopy (trace.endpos, ent->v.origin);
1369                 SV_LinkEdict (ent, false);
1370                 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1371                 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1372                 G_FLOAT(OFS_RETURN) = 1;
1373                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1374                 ent->suspendedinairflag = true;
1375         }
1376 }
1377
1378 /*
1379 ===============
1380 PF_lightstyle
1381
1382 void(float style, string value) lightstyle
1383 ===============
1384 */
1385 void PF_lightstyle (void)
1386 {
1387         int             style;
1388         char    *val;
1389         client_t        *client;
1390         int                     j;
1391
1392         style = G_FLOAT(OFS_PARM0);
1393         val = G_STRING(OFS_PARM1);
1394
1395 // change the string in sv
1396         sv.lightstyles[style] = val;
1397
1398 // send message to all clients on this server
1399         if (sv.state != ss_active)
1400                 return;
1401
1402         for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1403                 if (client->active || client->spawned)
1404                 {
1405                         MSG_WriteChar (&client->message, svc_lightstyle);
1406                         MSG_WriteChar (&client->message,style);
1407                         MSG_WriteString (&client->message, val);
1408                 }
1409 }
1410
1411 void PF_rint (void)
1412 {
1413         float   f;
1414         f = G_FLOAT(OFS_PARM0);
1415         if (f > 0)
1416                 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1417         else
1418                 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1419 }
1420 void PF_floor (void)
1421 {
1422         G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1423 }
1424 void PF_ceil (void)
1425 {
1426         G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1427 }
1428
1429
1430 /*
1431 =============
1432 PF_checkbottom
1433 =============
1434 */
1435 void PF_checkbottom (void)
1436 {
1437         G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1438 }
1439
1440 /*
1441 =============
1442 PF_pointcontents
1443 =============
1444 */
1445 void PF_pointcontents (void)
1446 {
1447         G_FLOAT(OFS_RETURN) = Mod_PointInLeaf(G_VECTOR(OFS_PARM0), sv.worldmodel)->contents;
1448 }
1449
1450 /*
1451 =============
1452 PF_nextent
1453
1454 entity nextent(entity)
1455 =============
1456 */
1457 void PF_nextent (void)
1458 {
1459         int             i;
1460         edict_t *ent;
1461
1462         i = G_EDICTNUM(OFS_PARM0);
1463         while (1)
1464         {
1465                 i++;
1466                 if (i == sv.num_edicts)
1467                 {
1468                         RETURN_EDICT(sv.edicts);
1469                         return;
1470                 }
1471                 ent = EDICT_NUM(i);
1472                 if (!ent->free)
1473                 {
1474                         RETURN_EDICT(ent);
1475                         return;
1476                 }
1477         }
1478 }
1479
1480 /*
1481 =============
1482 PF_aim
1483
1484 Pick a vector for the player to shoot along
1485 vector aim(entity, missilespeed)
1486 =============
1487 */
1488 void PF_aim (void)
1489 {
1490         edict_t *ent, *check, *bestent;
1491         vec3_t  start, dir, end, bestdir;
1492         int             i, j;
1493         trace_t tr;
1494         float   dist, bestdist;
1495         float   speed;
1496
1497         ent = G_EDICT(OFS_PARM0);
1498         speed = G_FLOAT(OFS_PARM1);
1499
1500         VectorCopy (ent->v.origin, start);
1501         start[2] += 20;
1502
1503 // try sending a trace straight
1504         VectorCopy (pr_global_struct->v_forward, dir);
1505         VectorMA (start, 2048, dir, end);
1506         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1507         if (tr.ent && ((edict_t *)tr.ent)->v.takedamage == DAMAGE_AIM
1508         && (!teamplay.integer || ent->v.team <=0 || ent->v.team != ((edict_t *)tr.ent)->v.team) )
1509         {
1510                 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1511                 return;
1512         }
1513
1514
1515 // try all possible entities
1516         VectorCopy (dir, bestdir);
1517         bestdist = sv_aim.value;
1518         bestent = NULL;
1519
1520         check = NEXT_EDICT(sv.edicts);
1521         for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1522         {
1523                 if (check->v.takedamage != DAMAGE_AIM)
1524                         continue;
1525                 if (check == ent)
1526                         continue;
1527                 if (teamplay.integer && ent->v.team > 0 && ent->v.team == check->v.team)
1528                         continue;       // don't aim at teammate
1529                 for (j=0 ; j<3 ; j++)
1530                         end[j] = check->v.origin[j]
1531                         + 0.5*(check->v.mins[j] + check->v.maxs[j]);
1532                 VectorSubtract (end, start, dir);
1533                 VectorNormalize (dir);
1534                 dist = DotProduct (dir, pr_global_struct->v_forward);
1535                 if (dist < bestdist)
1536                         continue;       // to far to turn
1537                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1538                 if (tr.ent == check)
1539                 {       // can shoot at this one
1540                         bestdist = dist;
1541                         bestent = check;
1542                 }
1543         }
1544
1545         if (bestent)
1546         {
1547                 VectorSubtract (bestent->v.origin, ent->v.origin, dir);
1548                 dist = DotProduct (dir, pr_global_struct->v_forward);
1549                 VectorScale (pr_global_struct->v_forward, dist, end);
1550                 end[2] = dir[2];
1551                 VectorNormalize (end);
1552                 VectorCopy (end, G_VECTOR(OFS_RETURN));
1553         }
1554         else
1555         {
1556                 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1557         }
1558 }
1559
1560 /*
1561 ==============
1562 PF_changeyaw
1563
1564 This was a major timewaster in progs, so it was converted to C
1565 ==============
1566 */
1567 void PF_changeyaw (void)
1568 {
1569         edict_t         *ent;
1570         float           ideal, current, move, speed;
1571
1572         ent = PROG_TO_EDICT(pr_global_struct->self);
1573         current = ANGLEMOD(ent->v.angles[1]);
1574         ideal = ent->v.ideal_yaw;
1575         speed = ent->v.yaw_speed;
1576
1577         if (current == ideal)
1578                 return;
1579         move = ideal - current;
1580         if (ideal > current)
1581         {
1582                 if (move >= 180)
1583                         move = move - 360;
1584         }
1585         else
1586         {
1587                 if (move <= -180)
1588                         move = move + 360;
1589         }
1590         if (move > 0)
1591         {
1592                 if (move > speed)
1593                         move = speed;
1594         }
1595         else
1596         {
1597                 if (move < -speed)
1598                         move = -speed;
1599         }
1600
1601         ent->v.angles[1] = ANGLEMOD (current + move);
1602 }
1603
1604 /*
1605 ==============
1606 PF_changepitch
1607 ==============
1608 */
1609 void PF_changepitch (void)
1610 {
1611         edict_t         *ent;
1612         float           ideal, current, move, speed;
1613         eval_t          *val;
1614
1615         ent = G_EDICT(OFS_PARM0);
1616         current = ANGLEMOD( ent->v.angles[0] );
1617         if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1618                 ideal = val->_float;
1619         else
1620         {
1621                 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1622                 return;
1623         }
1624         if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1625                 speed = val->_float;
1626         else
1627         {
1628                 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1629                 return;
1630         }
1631
1632         if (current == ideal)
1633                 return;
1634         move = ideal - current;
1635         if (ideal > current)
1636         {
1637                 if (move >= 180)
1638                         move = move - 360;
1639         }
1640         else
1641         {
1642                 if (move <= -180)
1643                         move = move + 360;
1644         }
1645         if (move > 0)
1646         {
1647                 if (move > speed)
1648                         move = speed;
1649         }
1650         else
1651         {
1652                 if (move < -speed)
1653                         move = -speed;
1654         }
1655
1656         ent->v.angles[0] = ANGLEMOD (current + move);
1657 }
1658
1659 /*
1660 ===============================================================================
1661
1662 MESSAGE WRITING
1663
1664 ===============================================================================
1665 */
1666
1667 #define MSG_BROADCAST   0               // unreliable to all
1668 #define MSG_ONE                 1               // reliable to one (msg_entity)
1669 #define MSG_ALL                 2               // reliable to all
1670 #define MSG_INIT                3               // write to the init string
1671
1672 sizebuf_t *WriteDest (void)
1673 {
1674         int             entnum;
1675         int             dest;
1676         edict_t *ent;
1677
1678         dest = G_FLOAT(OFS_PARM0);
1679         switch (dest)
1680         {
1681         case MSG_BROADCAST:
1682                 return &sv.datagram;
1683
1684         case MSG_ONE:
1685                 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1686                 entnum = NUM_FOR_EDICT(ent);
1687                 if (entnum < 1 || entnum > svs.maxclients)
1688                         PR_RunError ("WriteDest: not a client");
1689                 return &svs.clients[entnum-1].message;
1690
1691         case MSG_ALL:
1692                 return &sv.reliable_datagram;
1693
1694         case MSG_INIT:
1695                 return &sv.signon;
1696
1697         default:
1698                 PR_RunError ("WriteDest: bad destination");
1699                 break;
1700         }
1701
1702         return NULL;
1703 }
1704
1705 void PF_WriteByte (void)
1706 {
1707         MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1708 }
1709
1710 void PF_WriteChar (void)
1711 {
1712         MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1713 }
1714
1715 void PF_WriteShort (void)
1716 {
1717         MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1718 }
1719
1720 void PF_WriteLong (void)
1721 {
1722         MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1723 }
1724
1725 void PF_WriteAngle (void)
1726 {
1727         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1728 }
1729
1730 void PF_WriteCoord (void)
1731 {
1732         MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1733 }
1734
1735 void PF_WriteString (void)
1736 {
1737         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1738 }
1739
1740
1741 void PF_WriteEntity (void)
1742 {
1743         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1744 }
1745
1746 //=============================================================================
1747
1748 int SV_ModelIndex (char *name);
1749
1750 void PF_makestatic (void)
1751 {
1752         edict_t *ent;
1753         int             i, large;
1754
1755         ent = G_EDICT(OFS_PARM0);
1756
1757         large = false;
1758         if (ent->v.modelindex >= 256 || ent->v.frame >= 256)
1759                 large = true;
1760
1761         if (large)
1762         {
1763                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1764                 MSG_WriteShort (&sv.signon, ent->v.modelindex);
1765                 MSG_WriteShort (&sv.signon, ent->v.frame);
1766         }
1767         else
1768         {
1769                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1770                 MSG_WriteByte (&sv.signon, ent->v.modelindex);
1771                 MSG_WriteByte (&sv.signon, ent->v.frame);
1772         }
1773
1774         MSG_WriteByte (&sv.signon, ent->v.colormap);
1775         MSG_WriteByte (&sv.signon, ent->v.skin);
1776         for (i=0 ; i<3 ; i++)
1777         {
1778                 MSG_WriteDPCoord(&sv.signon, ent->v.origin[i]);
1779                 MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1780         }
1781
1782 // throw the entity away now
1783         ED_Free (ent);
1784 }
1785
1786 //=============================================================================
1787
1788 /*
1789 ==============
1790 PF_setspawnparms
1791 ==============
1792 */
1793 void PF_setspawnparms (void)
1794 {
1795         edict_t *ent;
1796         int             i;
1797         client_t        *client;
1798
1799         ent = G_EDICT(OFS_PARM0);
1800         i = NUM_FOR_EDICT(ent);
1801         if (i < 1 || i > svs.maxclients)
1802                 PR_RunError ("Entity is not a client");
1803
1804         // copy spawn parms out of the client_t
1805         client = svs.clients + (i-1);
1806
1807         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1808                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1809 }
1810
1811 /*
1812 ==============
1813 PF_changelevel
1814 ==============
1815 */
1816 void PF_changelevel (void)
1817 {
1818         char    *s;
1819
1820 // make sure we don't issue two changelevels
1821         if (svs.changelevel_issued)
1822                 return;
1823         svs.changelevel_issued = true;
1824
1825         s = G_STRING(OFS_PARM0);
1826         Cbuf_AddText (va("changelevel %s\n",s));
1827 }
1828
1829 void PF_sin (void)
1830 {
1831         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1832 }
1833
1834 void PF_cos (void)
1835 {
1836         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1837 }
1838
1839 void PF_sqrt (void)
1840 {
1841         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1842 }
1843
1844 /*
1845 =================
1846 PF_RandomVec
1847
1848 Returns a vector of length < 1
1849
1850 randomvec()
1851 =================
1852 */
1853 void PF_randomvec (void)
1854 {
1855         vec3_t          temp;
1856         do
1857         {
1858                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1859                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1860                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1861         }
1862         while (DotProduct(temp, temp) >= 1);
1863         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1864 }
1865
1866 void SV_LightPoint (vec3_t color, vec3_t p);
1867 /*
1868 =================
1869 PF_GetLight
1870
1871 Returns a color vector indicating the lighting at the requested point.
1872
1873 (Internal Operation note: actually measures the light beneath the point, just like
1874                           the model lighting on the client)
1875
1876 getlight(vector)
1877 =================
1878 */
1879 void PF_GetLight (void)
1880 {
1881         vec3_t          color;
1882         vec_t*          p;
1883         p = G_VECTOR(OFS_PARM0);
1884         SV_LightPoint (color, p);
1885         VectorCopy (color, G_VECTOR(OFS_RETURN));
1886 }
1887
1888 #define MAX_QC_CVARS 128
1889 cvar_t qc_cvar[MAX_QC_CVARS];
1890 int currentqc_cvar;
1891
1892 void PF_registercvar (void)
1893 {
1894         char    *name, *value;
1895         cvar_t  *variable;
1896         name = G_STRING(OFS_PARM0);
1897         value = G_STRING(OFS_PARM1);
1898         G_FLOAT(OFS_RETURN) = 0;
1899 // first check to see if it has already been defined
1900         if (Cvar_FindVar (name))
1901                 return;
1902
1903 // check for overlap with a command
1904         if (Cmd_Exists (name))
1905         {
1906                 Con_Printf ("PF_registercvar: %s is a command\n", name);
1907                 return;
1908         }
1909
1910         if (currentqc_cvar >= MAX_QC_CVARS)
1911                 PR_RunError ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1912
1913 // copy the name and value
1914         variable = &qc_cvar[currentqc_cvar++];
1915         variable->name = Z_Malloc (strlen(name)+1);
1916         strcpy (variable->name, name);
1917         variable->string = Z_Malloc (strlen(value)+1);
1918         strcpy (variable->string, value);
1919         variable->value = atof (value);
1920
1921 // link the variable in
1922         variable->next = cvar_vars;
1923         cvar_vars = 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