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