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