]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
q1bsp lightmaps are now always rendered at 2x overbright like software quake and...
[divverent/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
25
26 mempool_t *pr_strings_mempool;
27
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
33
34 static char *PR_GetTempString(void)
35 {
36         char *s;
37         s = pr_string_temp[pr_string_tempindex];
38         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
39         return s;
40 }
41
42 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
43
44
45 /*
46 ===============================================================================
47
48                                                 BUILT-IN FUNCTIONS
49
50 ===============================================================================
51 */
52
53
54 void PF_VarString(int first, char *out, int outlength)
55 {
56         int i;
57         const char *s;
58         char *outend;
59
60         outend = out + outlength - 1;
61         for (i = first;i < pr_argc && out < outend;i++)
62         {
63                 s = G_STRING((OFS_PARM0+i*3));
64                 while (out < outend && *s)
65                         *out++ = *s++;
66         }
67         *out++ = 0;
68 }
69
70 char *ENGINE_EXTENSIONS =
71 "DP_CL_LOADSKY "
72 "DP_EF_NODRAW "
73 "DP_EF_ADDITIVE "
74 "DP_EF_BLUE "
75 "DP_EF_RED "
76 "DP_EF_FULLBRIGHT "
77 "DP_EF_FLAME "
78 "DP_EF_STARDUST "
79 "DP_ENT_ALPHA "
80 "DP_ENT_CUSTOMCOLORMAP "
81 "DP_ENT_EXTERIORMODELTOCLIENT "
82 "DP_ENT_LOWPRECISION "
83 "DP_ENT_GLOW "
84 "DP_ENT_SCALE "
85 "DP_ENT_VIEWMODEL "
86 "DP_GFX_EXTERNALTEXTURES "
87 "DP_GFX_FOG "
88 "DP_GFX_QUAKE3MODELTAGS "
89 "DP_GFX_SKINFILES "
90 "DP_GFX_SKYBOX "
91 "DP_HALFLIFE_MAP "
92 "DP_HALFLIFE_MAP_CVAR "
93 "DP_INPUTBUTTONS "
94 "DP_MONSTERWALK "
95 "DP_MOVETYPEBOUNCEMISSILE "
96 "DP_MOVETYPEFOLLOW "
97 "DP_QC_CHANGEPITCH "
98 "DP_QC_COPYENTITY "
99 "DP_QC_ETOS "
100 "DP_QC_FINDCHAIN "
101 "DP_QC_FINDCHAINFLOAT "
102 "DP_QC_FINDFLOAT "
103 "DP_QC_GETLIGHT "
104 "DP_QC_GETSURFACE "
105 "DP_QC_MINMAXBOUND "
106 "DP_QC_RANDOMVEC "
107 "DP_QC_SINCOSSQRTPOW "
108 "DP_QC_TRACEBOX "
109 "DP_QC_TRACETOSS "
110 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
111 "DP_QC_TRACE_MOVETYPE_HITMODEL "
112 "DP_QC_VECTORVECTORS "
113 "DP_QUAKE2_MODEL "
114 "DP_QUAKE3_MODEL "
115 "DP_REGISTERCVAR "
116 "DP_SOLIDCORPSE "
117 "DP_SPRITE32 "
118 "DP_SV_DRAWONLYTOCLIENT "
119 "DP_SV_EFFECT "
120 "DP_SV_EXTERIORMODELTOCLIENT "
121 "DP_SV_NODRAWTOCLIENT "
122 "DP_SV_PLAYERPHYSICS "
123 "DP_SV_SETCOLOR "
124 "DP_SV_SLOWMO "
125 "DP_TE_BLOOD "
126 "DP_TE_BLOODSHOWER "
127 "DP_TE_CUSTOMFLASH "
128 "DP_TE_EXPLOSIONRGB "
129 "DP_TE_FLAMEJET "
130 "DP_TE_PARTICLECUBE "
131 "DP_TE_PARTICLERAIN "
132 "DP_TE_PARTICLESNOW "
133 "DP_TE_PLASMABURN "
134 "DP_TE_QUADEFFECTS1 "
135 "DP_TE_SMALLFLASH "
136 "DP_TE_SPARK "
137 "DP_TE_STANDARDEFFECTBUILTINS "
138 "DP_VIEWZOOM "
139 "FRIK_FILE "
140 "KRIMZON_SV_PARSECLIENTCOMMAND "
141 "NEH_CMD_PLAY2 "
142 "NEH_RESTOREGAME "
143 "TW_SV_STEPCONTROL "
144 ;
145
146 qboolean checkextension(char *name)
147 {
148         int len;
149         char *e, *start;
150         len = strlen(name);
151         for (e = ENGINE_EXTENSIONS;*e;e++)
152         {
153                 while (*e == ' ')
154                         e++;
155                 if (!*e)
156                         break;
157                 start = e;
158                 while (*e && *e != ' ')
159                         e++;
160                 if (e - start == len)
161                         if (!strncasecmp(start, name, len))
162                                 return true;
163         }
164         return false;
165 }
166
167 /*
168 =================
169 PF_checkextension
170
171 returns true if the extension is supported by the server
172
173 checkextension(extensionname)
174 =================
175 */
176 void PF_checkextension (void)
177 {
178         G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
179 }
180
181 /*
182 =================
183 PF_error
184
185 This is a TERMINAL error, which will kill off the entire server.
186 Dumps self.
187
188 error(value)
189 =================
190 */
191 void PF_error (void)
192 {
193         edict_t *ed;
194         char string[STRINGTEMP_LENGTH];
195
196         PF_VarString(0, string, sizeof(string));
197         Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
198         ed = PROG_TO_EDICT(pr_global_struct->self);
199         ED_Print (ed);
200
201         Host_Error ("Program error");
202 }
203
204 /*
205 =================
206 PF_objerror
207
208 Dumps out self, then an error message.  The program is aborted and self is
209 removed, but the level can continue.
210
211 objerror(value)
212 =================
213 */
214 void PF_objerror (void)
215 {
216         edict_t *ed;
217         char string[STRINGTEMP_LENGTH];
218
219         PF_VarString(0, string, sizeof(string));
220         Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
221         ed = PROG_TO_EDICT(pr_global_struct->self);
222         ED_Print (ed);
223         ED_Free (ed);
224 }
225
226
227 /*
228 ==============
229 PF_makevectors
230
231 Writes new values for v_forward, v_up, and v_right based on angles
232 makevectors(vector)
233 ==============
234 */
235 void PF_makevectors (void)
236 {
237         AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
238 }
239
240 /*
241 ==============
242 PF_vectorvectors
243
244 Writes new values for v_forward, v_up, and v_right based on the given forward vector
245 vectorvectors(vector, vector)
246 ==============
247 */
248 void PF_vectorvectors (void)
249 {
250         VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
251         VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
252 }
253
254 /*
255 =================
256 PF_setorigin
257
258 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.
259
260 setorigin (entity, origin)
261 =================
262 */
263 void PF_setorigin (void)
264 {
265         edict_t *e;
266         float   *org;
267
268         e = G_EDICT(OFS_PARM0);
269         if (e == sv.edicts)
270                 Host_Error("setorigin: can not modify world entity\n");
271         if (e->e->free)
272                 Host_Error("setorigin: can not modify free entity\n");
273         org = G_VECTOR(OFS_PARM1);
274         VectorCopy (org, e->v->origin);
275         SV_LinkEdict (e, false);
276 }
277
278
279 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
280 {
281         int             i;
282
283         for (i=0 ; i<3 ; i++)
284                 if (min[i] > max[i])
285                         Host_Error ("backwards mins/maxs");
286
287 // set derived values
288         VectorCopy (min, e->v->mins);
289         VectorCopy (max, e->v->maxs);
290         VectorSubtract (max, min, e->v->size);
291
292         SV_LinkEdict (e, false);
293 }
294
295 /*
296 =================
297 PF_setsize
298
299 the size box is rotated by the current angle
300 LordHavoc: no it isn't...
301
302 setsize (entity, minvector, maxvector)
303 =================
304 */
305 void PF_setsize (void)
306 {
307         edict_t *e;
308         float   *min, *max;
309
310         e = G_EDICT(OFS_PARM0);
311         if (e == sv.edicts)
312                 Host_Error("setsize: can not modify world entity\n");
313         if (e->e->free)
314                 Host_Error("setsize: can not modify free entity\n");
315         min = G_VECTOR(OFS_PARM1);
316         max = G_VECTOR(OFS_PARM2);
317         SetMinMaxSize (e, min, max, false);
318 }
319
320
321 /*
322 =================
323 PF_setmodel
324
325 setmodel(entity, model)
326 =================
327 */
328 void PF_setmodel (void)
329 {
330         edict_t *e;
331         char    *m, **check;
332         model_t *mod;
333         int             i;
334
335         e = G_EDICT(OFS_PARM0);
336         if (e == sv.edicts)
337                 Host_Error("setmodel: can not modify world entity\n");
338         if (e->e->free)
339                 Host_Error("setmodel: can not modify free entity\n");
340         m = G_STRING(OFS_PARM1);
341
342 // check to see if model was properly precached
343         for (i=0, check = sv.model_precache ; *check ; i++, check++)
344                 if (!strcmp(*check, m))
345                         break;
346
347         if (!*check)
348                 Host_Error ("no precache: %s\n", m);
349
350
351         e->v->model = PR_SetString(*check);
352         e->v->modelindex = i;
353
354         mod = sv.models[ (int)e->v->modelindex];
355
356         if (mod)
357                 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
358         else
359                 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
360 }
361
362 /*
363 =================
364 PF_bprint
365
366 broadcast print to everyone on server
367
368 bprint(value)
369 =================
370 */
371 void PF_bprint (void)
372 {
373         char string[STRINGTEMP_LENGTH];
374         PF_VarString(0, string, sizeof(string));
375         SV_BroadcastPrintf("%s", string);
376 }
377
378 /*
379 =================
380 PF_sprint
381
382 single print to a specific client
383
384 sprint(clientent, value)
385 =================
386 */
387 void PF_sprint (void)
388 {
389         client_t        *client;
390         int                     entnum;
391         char string[STRINGTEMP_LENGTH];
392
393         entnum = G_EDICTNUM(OFS_PARM0);
394
395         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
396         {
397                 Con_Printf ("tried to sprint to a non-client\n");
398                 return;
399         }
400
401         client = svs.clients + entnum-1;
402         if (!client->netconnection)
403                 return;
404         PF_VarString(1, string, sizeof(string));
405         MSG_WriteChar(&client->message,svc_print);
406         MSG_WriteString(&client->message, string);
407 }
408
409
410 /*
411 =================
412 PF_centerprint
413
414 single print to a specific client
415
416 centerprint(clientent, value)
417 =================
418 */
419 void PF_centerprint (void)
420 {
421         client_t        *client;
422         int                     entnum;
423         char string[STRINGTEMP_LENGTH];
424
425         entnum = G_EDICTNUM(OFS_PARM0);
426
427         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
428         {
429                 Con_Printf ("tried to sprint to a non-client\n");
430                 return;
431         }
432
433         client = svs.clients + entnum-1;
434         if (!client->netconnection)
435                 return;
436         PF_VarString(1, string, sizeof(string));
437         MSG_WriteChar(&client->message,svc_centerprint);
438         MSG_WriteString(&client->message, string);
439 }
440
441
442 /*
443 =================
444 PF_normalize
445
446 vector normalize(vector)
447 =================
448 */
449 void PF_normalize (void)
450 {
451         float   *value1;
452         vec3_t  newvalue;
453         float   new;
454
455         value1 = G_VECTOR(OFS_PARM0);
456
457         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
458         new = sqrt(new);
459
460         if (new == 0)
461                 newvalue[0] = newvalue[1] = newvalue[2] = 0;
462         else
463         {
464                 new = 1/new;
465                 newvalue[0] = value1[0] * new;
466                 newvalue[1] = value1[1] * new;
467                 newvalue[2] = value1[2] * new;
468         }
469
470         VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
471 }
472
473 /*
474 =================
475 PF_vlen
476
477 scalar vlen(vector)
478 =================
479 */
480 void PF_vlen (void)
481 {
482         float   *value1;
483         float   new;
484
485         value1 = G_VECTOR(OFS_PARM0);
486
487         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
488         new = sqrt(new);
489
490         G_FLOAT(OFS_RETURN) = new;
491 }
492
493 /*
494 =================
495 PF_vectoyaw
496
497 float vectoyaw(vector)
498 =================
499 */
500 void PF_vectoyaw (void)
501 {
502         float   *value1;
503         float   yaw;
504
505         value1 = G_VECTOR(OFS_PARM0);
506
507         if (value1[1] == 0 && value1[0] == 0)
508                 yaw = 0;
509         else
510         {
511                 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
512                 if (yaw < 0)
513                         yaw += 360;
514         }
515
516         G_FLOAT(OFS_RETURN) = yaw;
517 }
518
519
520 /*
521 =================
522 PF_vectoangles
523
524 vector vectoangles(vector)
525 =================
526 */
527 void PF_vectoangles (void)
528 {
529         float   *value1;
530         float   forward;
531         float   yaw, pitch;
532
533         value1 = G_VECTOR(OFS_PARM0);
534
535         if (value1[1] == 0 && value1[0] == 0)
536         {
537                 yaw = 0;
538                 if (value1[2] > 0)
539                         pitch = 90;
540                 else
541                         pitch = 270;
542         }
543         else
544         {
545                 // LordHavoc: optimized a bit
546                 if (value1[0])
547                 {
548                         yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
549                         if (yaw < 0)
550                                 yaw += 360;
551                 }
552                 else if (value1[1] > 0)
553                         yaw = 90;
554                 else
555                         yaw = 270;
556
557                 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
558                 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
559                 if (pitch < 0)
560                         pitch += 360;
561         }
562
563         G_FLOAT(OFS_RETURN+0) = pitch;
564         G_FLOAT(OFS_RETURN+1) = yaw;
565         G_FLOAT(OFS_RETURN+2) = 0;
566 }
567
568 /*
569 =================
570 PF_Random
571
572 Returns a number from 0<= num < 1
573
574 random()
575 =================
576 */
577 void PF_random (void)
578 {
579         float           num;
580
581         num = (rand ()&0x7fff) / ((float)0x7fff);
582
583         G_FLOAT(OFS_RETURN) = num;
584 }
585
586 /*
587 =================
588 PF_particle
589
590 particle(origin, color, count)
591 =================
592 */
593 void PF_particle (void)
594 {
595         float           *org, *dir;
596         float           color;
597         float           count;
598
599         org = G_VECTOR(OFS_PARM0);
600         dir = G_VECTOR(OFS_PARM1);
601         color = G_FLOAT(OFS_PARM2);
602         count = G_FLOAT(OFS_PARM3);
603         SV_StartParticle (org, dir, color, count);
604 }
605
606
607 /*
608 =================
609 PF_ambientsound
610
611 =================
612 */
613 void PF_ambientsound (void)
614 {
615         char            **check;
616         char            *samp;
617         float           *pos;
618         float           vol, attenuation;
619         int                     i, soundnum, large;
620
621         pos = G_VECTOR (OFS_PARM0);
622         samp = G_STRING(OFS_PARM1);
623         vol = G_FLOAT(OFS_PARM2);
624         attenuation = G_FLOAT(OFS_PARM3);
625
626 // check to see if samp was properly precached
627         for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
628                 if (!strcmp(*check,samp))
629                         break;
630
631         if (!*check)
632         {
633                 Con_Printf ("no precache: %s\n", samp);
634                 return;
635         }
636
637         large = false;
638         if (soundnum >= 256)
639                 large = true;
640
641         // add an svc_spawnambient command to the level signon packet
642
643         if (large)
644                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
645         else
646                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
647
648         for (i=0 ; i<3 ; i++)
649                 MSG_WriteDPCoord(&sv.signon, pos[i]);
650
651         if (large)
652                 MSG_WriteShort (&sv.signon, soundnum);
653         else
654                 MSG_WriteByte (&sv.signon, soundnum);
655
656         MSG_WriteByte (&sv.signon, vol*255);
657         MSG_WriteByte (&sv.signon, attenuation*64);
658
659 }
660
661 /*
662 =================
663 PF_sound
664
665 Each entity can have eight independant sound sources, like voice,
666 weapon, feet, etc.
667
668 Channel 0 is an auto-allocate channel, the others override anything
669 already running on that entity/channel pair.
670
671 An attenuation of 0 will play full volume everywhere in the level.
672 Larger attenuations will drop off.
673
674 =================
675 */
676 void PF_sound (void)
677 {
678         char            *sample;
679         int                     channel;
680         edict_t         *entity;
681         int             volume;
682         float attenuation;
683
684         entity = G_EDICT(OFS_PARM0);
685         channel = G_FLOAT(OFS_PARM1);
686         sample = G_STRING(OFS_PARM2);
687         volume = G_FLOAT(OFS_PARM3) * 255;
688         attenuation = G_FLOAT(OFS_PARM4);
689
690         if (volume < 0 || volume > 255)
691                 Host_Error ("SV_StartSound: volume = %i", volume);
692
693         if (attenuation < 0 || attenuation > 4)
694                 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
695
696         if (channel < 0 || channel > 7)
697                 Host_Error ("SV_StartSound: channel = %i", channel);
698
699         SV_StartSound (entity, channel, sample, volume, attenuation);
700 }
701
702 /*
703 =================
704 PF_break
705
706 break()
707 =================
708 */
709 void PF_break (void)
710 {
711         Host_Error ("break statement");
712 }
713
714 /*
715 =================
716 PF_traceline
717
718 Used for use tracing and shot targeting
719 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
720 if the tryents flag is set.
721
722 traceline (vector1, vector2, tryents)
723 =================
724 */
725 void PF_traceline (void)
726 {
727         float   *v1, *v2;
728         trace_t trace;
729         int             nomonsters;
730         edict_t *ent;
731
732         pr_xfunction->builtinsprofile += 30;
733
734         v1 = G_VECTOR(OFS_PARM0);
735         v2 = G_VECTOR(OFS_PARM1);
736         nomonsters = G_FLOAT(OFS_PARM2);
737         ent = G_EDICT(OFS_PARM3);
738
739         trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
740
741         pr_global_struct->trace_allsolid = trace.allsolid;
742         pr_global_struct->trace_startsolid = trace.startsolid;
743         pr_global_struct->trace_fraction = trace.fraction;
744         pr_global_struct->trace_inwater = trace.inwater;
745         pr_global_struct->trace_inopen = trace.inopen;
746         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
747         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
748         pr_global_struct->trace_plane_dist =  trace.plane.dist;
749         if (trace.ent)
750                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
751         else
752                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
753         // FIXME: add trace_endcontents
754 }
755
756
757 /*
758 =================
759 PF_tracebox
760
761 Used for use tracing and shot targeting
762 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
763 if the tryents flag is set.
764
765 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
766 =================
767 */
768 // LordHavoc: added this for my own use, VERY useful, similar to traceline
769 void PF_tracebox (void)
770 {
771         float   *v1, *v2, *m1, *m2;
772         trace_t trace;
773         int             nomonsters;
774         edict_t *ent;
775
776         pr_xfunction->builtinsprofile += 30;
777
778         v1 = G_VECTOR(OFS_PARM0);
779         m1 = G_VECTOR(OFS_PARM1);
780         m2 = G_VECTOR(OFS_PARM2);
781         v2 = G_VECTOR(OFS_PARM3);
782         nomonsters = G_FLOAT(OFS_PARM4);
783         ent = G_EDICT(OFS_PARM5);
784
785         trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
786
787         pr_global_struct->trace_allsolid = trace.allsolid;
788         pr_global_struct->trace_startsolid = trace.startsolid;
789         pr_global_struct->trace_fraction = trace.fraction;
790         pr_global_struct->trace_inwater = trace.inwater;
791         pr_global_struct->trace_inopen = trace.inopen;
792         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
793         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
794         pr_global_struct->trace_plane_dist =  trace.plane.dist;
795         if (trace.ent)
796                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
797         else
798                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
799 }
800
801 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
802 void PF_TraceToss (void)
803 {
804         trace_t trace;
805         edict_t *ent;
806         edict_t *ignore;
807
808         pr_xfunction->builtinsprofile += 600;
809
810         ent = G_EDICT(OFS_PARM0);
811         if (ent == sv.edicts)
812                 Host_Error("tracetoss: can not use world entity\n");
813         ignore = G_EDICT(OFS_PARM1);
814
815         trace = SV_Trace_Toss (ent, ignore);
816
817         pr_global_struct->trace_allsolid = trace.allsolid;
818         pr_global_struct->trace_startsolid = trace.startsolid;
819         pr_global_struct->trace_fraction = trace.fraction;
820         pr_global_struct->trace_inwater = trace.inwater;
821         pr_global_struct->trace_inopen = trace.inopen;
822         VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
823         VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
824         pr_global_struct->trace_plane_dist =  trace.plane.dist;
825         if (trace.ent)
826                 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
827         else
828                 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
829 }
830
831
832 /*
833 =================
834 PF_checkpos
835
836 Returns true if the given entity can move to the given position from it's
837 current position by walking or rolling.
838 FIXME: make work...
839 scalar checkpos (entity, vector)
840 =================
841 */
842 void PF_checkpos (void)
843 {
844 }
845
846 //============================================================================
847
848 int checkpvsbytes;
849 qbyte checkpvs[MAX_MAP_LEAFS/8];
850
851 int PF_newcheckclient (int check)
852 {
853         int             i;
854         edict_t *ent;
855         vec3_t  org;
856
857 // cycle to the next one
858
859         check = bound(1, check, svs.maxclients);
860         if (check == svs.maxclients)
861                 i = 1;
862         else
863                 i = check + 1;
864
865         for ( ;  ; i++)
866         {
867                 // count the cost
868                 pr_xfunction->builtinsprofile++;
869                 // wrap around
870                 if (i == svs.maxclients+1)
871                         i = 1;
872                 // look up the client's edict
873                 ent = EDICT_NUM(i);
874                 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
875                 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
876                         continue;
877                 // found a valid client (possibly the same one again)
878                 break;
879         }
880
881 // get the PVS for the entity
882         VectorAdd(ent->v->origin, ent->v->view_ofs, org);
883         checkpvsbytes = 0;
884         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
885                 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
886
887         return i;
888 }
889
890 /*
891 =================
892 PF_checkclient
893
894 Returns a client (or object that has a client enemy) that would be a
895 valid target.
896
897 If there is more than one valid option, they are cycled each frame
898
899 If (self.origin + self.viewofs) is not in the PVS of the current target,
900 it is not returned at all.
901
902 name checkclient ()
903 =================
904 */
905 int c_invis, c_notvis;
906 void PF_checkclient (void)
907 {
908         edict_t *ent, *self;
909         vec3_t  view;
910
911         // find a new check if on a new frame
912         if (sv.time - sv.lastchecktime >= 0.1)
913         {
914                 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
915                 sv.lastchecktime = sv.time;
916         }
917
918         // return check if it might be visible
919         ent = EDICT_NUM(sv.lastcheck);
920         if (ent->e->free || ent->v->health <= 0)
921         {
922                 RETURN_EDICT(sv.edicts);
923                 return;
924         }
925
926         // if current entity can't possibly see the check entity, return 0
927         self = PROG_TO_EDICT(pr_global_struct->self);
928         VectorAdd(self->v->origin, self->v->view_ofs, view);
929         if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
930         {
931                 c_notvis++;
932                 RETURN_EDICT(sv.edicts);
933                 return;
934         }
935
936         // might be able to see it
937         c_invis++;
938         RETURN_EDICT(ent);
939 }
940
941 //============================================================================
942
943
944 /*
945 =================
946 PF_stuffcmd
947
948 Sends text over to the client's execution buffer
949
950 stuffcmd (clientent, value)
951 =================
952 */
953 void PF_stuffcmd (void)
954 {
955         int             entnum;
956         char    *str;
957         client_t        *old;
958
959         entnum = G_EDICTNUM(OFS_PARM0);
960         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
961         {
962                 Con_Printf("Can't stuffcmd to a non-client");
963                 return;
964         }
965         str = G_STRING(OFS_PARM1);
966
967         old = host_client;
968         if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
969                 Host_ClientCommands ("%s", str);
970         host_client = old;
971 }
972
973 /*
974 =================
975 PF_localcmd
976
977 Sends text to server console
978
979 localcmd (string)
980 =================
981 */
982 void PF_localcmd (void)
983 {
984         Cbuf_AddText(G_STRING(OFS_PARM0));
985 }
986
987 /*
988 =================
989 PF_cvar
990
991 float cvar (string)
992 =================
993 */
994 void PF_cvar (void)
995 {
996         G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
997 }
998
999 /*
1000 =================
1001 PF_cvar_set
1002
1003 float cvar (string)
1004 =================
1005 */
1006 void PF_cvar_set (void)
1007 {
1008         Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1009 }
1010
1011 /*
1012 =================
1013 PF_findradius
1014
1015 Returns a chain of entities that have origins within a spherical area
1016
1017 findradius (origin, radius)
1018 =================
1019 */
1020 void PF_findradius (void)
1021 {
1022         edict_t *ent, *chain;
1023         float radius;
1024         float radius2;
1025         float *org;
1026         float eorg[3];
1027         int i;
1028
1029         chain = (edict_t *)sv.edicts;
1030
1031         org = G_VECTOR(OFS_PARM0);
1032         radius = G_FLOAT(OFS_PARM1);
1033         radius2 = radius * radius;
1034
1035         ent = NEXT_EDICT(sv.edicts);
1036         for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1037         {
1038                 pr_xfunction->builtinsprofile++;
1039                 if (ent->e->free)
1040                         continue;
1041                 if (ent->v->solid == SOLID_NOT)
1042                         continue;
1043
1044                 // LordHavoc: compare against bounding box rather than center,
1045                 // and use DotProduct instead of Length, major speedup
1046                 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1047                 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1048                 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1049                 if (DotProduct(eorg, eorg) > radius2)
1050                         continue;
1051
1052                 ent->v->chain = EDICT_TO_PROG(chain);
1053                 chain = ent;
1054         }
1055
1056         RETURN_EDICT(chain);
1057 }
1058
1059
1060 /*
1061 =========
1062 PF_dprint
1063 =========
1064 */
1065 void PF_dprint (void)
1066 {
1067         char string[STRINGTEMP_LENGTH];
1068         if (developer.integer)
1069         {
1070                 PF_VarString(0, string, sizeof(string));
1071                 Con_Printf("%s",string);
1072         }
1073 }
1074
1075 void PF_ftos (void)
1076 {
1077         float v;
1078         char *s;
1079         v = G_FLOAT(OFS_PARM0);
1080
1081         s = PR_GetTempString();
1082         if ((float)((int)v) == v)
1083                 sprintf(s, "%i", (int)v);
1084         else
1085                 sprintf(s, "%f", v);
1086         G_INT(OFS_RETURN) = PR_SetString(s);
1087 }
1088
1089 void PF_fabs (void)
1090 {
1091         float   v;
1092         v = G_FLOAT(OFS_PARM0);
1093         G_FLOAT(OFS_RETURN) = fabs(v);
1094 }
1095
1096 void PF_vtos (void)
1097 {
1098         char *s;
1099         s = PR_GetTempString();
1100         sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1101         G_INT(OFS_RETURN) = PR_SetString(s);
1102 }
1103
1104 void PF_etos (void)
1105 {
1106         char *s;
1107         s = PR_GetTempString();
1108         sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1109         G_INT(OFS_RETURN) = PR_SetString(s);
1110 }
1111
1112 void PF_Spawn (void)
1113 {
1114         edict_t *ed;
1115         pr_xfunction->builtinsprofile += 20;
1116         ed = ED_Alloc();
1117         RETURN_EDICT(ed);
1118 }
1119
1120 void PF_Remove (void)
1121 {
1122         edict_t *ed;
1123         pr_xfunction->builtinsprofile += 20;
1124
1125         ed = G_EDICT(OFS_PARM0);
1126         if (ed == sv.edicts)
1127                 Host_Error("remove: tried to remove world\n");
1128         if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1129                 Host_Error("remove: tried to remove a client\n");
1130         if (ed->e->free)
1131                 Host_Error("remove: tried to remove an entity that was already removed\n");
1132         ED_Free (ed);
1133 }
1134
1135
1136 // entity (entity start, .string field, string match) find = #5;
1137 void PF_Find (void)
1138 {
1139         int             e;
1140         int             f;
1141         char    *s, *t;
1142         edict_t *ed;
1143
1144         e = G_EDICTNUM(OFS_PARM0);
1145         f = G_INT(OFS_PARM1);
1146         s = G_STRING(OFS_PARM2);
1147         if (!s || !s[0])
1148         {
1149                 RETURN_EDICT(sv.edicts);
1150                 return;
1151         }
1152
1153         for (e++ ; e < sv.num_edicts ; e++)
1154         {
1155                 pr_xfunction->builtinsprofile++;
1156                 ed = EDICT_NUM(e);
1157                 if (ed->e->free)
1158                         continue;
1159                 t = E_STRING(ed,f);
1160                 if (!t)
1161                         continue;
1162                 if (!strcmp(t,s))
1163                 {
1164                         RETURN_EDICT(ed);
1165                         return;
1166                 }
1167         }
1168
1169         RETURN_EDICT(sv.edicts);
1170 }
1171
1172 // LordHavoc: added this for searching float, int, and entity reference fields
1173 void PF_FindFloat (void)
1174 {
1175         int             e;
1176         int             f;
1177         float   s;
1178         edict_t *ed;
1179
1180         e = G_EDICTNUM(OFS_PARM0);
1181         f = G_INT(OFS_PARM1);
1182         s = G_FLOAT(OFS_PARM2);
1183
1184         for (e++ ; e < sv.num_edicts ; e++)
1185         {
1186                 pr_xfunction->builtinsprofile++;
1187                 ed = EDICT_NUM(e);
1188                 if (ed->e->free)
1189                         continue;
1190                 if (E_FLOAT(ed,f) == s)
1191                 {
1192                         RETURN_EDICT(ed);
1193                         return;
1194                 }
1195         }
1196
1197         RETURN_EDICT(sv.edicts);
1198 }
1199
1200 // chained search for strings in entity fields
1201 // entity(.string field, string match) findchain = #402;
1202 void PF_findchain (void)
1203 {
1204         int             i;
1205         int             f;
1206         char    *s, *t;
1207         edict_t *ent, *chain;
1208
1209         chain = (edict_t *)sv.edicts;
1210
1211         f = G_INT(OFS_PARM0);
1212         s = G_STRING(OFS_PARM1);
1213         if (!s || !s[0])
1214         {
1215                 RETURN_EDICT(sv.edicts);
1216                 return;
1217         }
1218
1219         ent = NEXT_EDICT(sv.edicts);
1220         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1221         {
1222                 pr_xfunction->builtinsprofile++;
1223                 if (ent->e->free)
1224                         continue;
1225                 t = E_STRING(ent,f);
1226                 if (!t)
1227                         continue;
1228                 if (strcmp(t,s))
1229                         continue;
1230
1231                 ent->v->chain = EDICT_TO_PROG(chain);
1232                 chain = ent;
1233         }
1234
1235         RETURN_EDICT(chain);
1236 }
1237
1238 // LordHavoc: chained search for float, int, and entity reference fields
1239 // entity(.string field, float match) findchainfloat = #403;
1240 void PF_findchainfloat (void)
1241 {
1242         int             i;
1243         int             f;
1244         float   s;
1245         edict_t *ent, *chain;
1246
1247         chain = (edict_t *)sv.edicts;
1248
1249         f = G_INT(OFS_PARM0);
1250         s = G_FLOAT(OFS_PARM1);
1251
1252         ent = NEXT_EDICT(sv.edicts);
1253         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1254         {
1255                 pr_xfunction->builtinsprofile++;
1256                 if (ent->e->free)
1257                         continue;
1258                 if (E_FLOAT(ent,f) != s)
1259                         continue;
1260
1261                 ent->v->chain = EDICT_TO_PROG(chain);
1262                 chain = ent;
1263         }
1264
1265         RETURN_EDICT(chain);
1266 }
1267
1268 void PR_CheckEmptyString (char *s)
1269 {
1270         if (s[0] <= ' ')
1271                 Host_Error ("Bad string");
1272 }
1273
1274 void PF_precache_file (void)
1275 {       // precache_file is only used to copy files with qcc, it does nothing
1276         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1277 }
1278
1279 void PF_precache_sound (void)
1280 {
1281         char    *s;
1282         int             i;
1283
1284         if (sv.state != ss_loading)
1285                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1286
1287         s = G_STRING(OFS_PARM0);
1288         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1289         PR_CheckEmptyString (s);
1290
1291         for (i=0 ; i<MAX_SOUNDS ; i++)
1292         {
1293                 if (!sv.sound_precache[i])
1294                 {
1295                         sv.sound_precache[i] = s;
1296                         return;
1297                 }
1298                 if (!strcmp(sv.sound_precache[i], s))
1299                         return;
1300         }
1301         Host_Error ("PF_precache_sound: overflow");
1302 }
1303
1304 void PF_precache_model (void)
1305 {
1306         char    *s;
1307         int             i;
1308
1309         if (sv.state != ss_loading)
1310                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1311
1312         s = G_STRING(OFS_PARM0);
1313         if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1314                 return;
1315         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1316         PR_CheckEmptyString (s);
1317
1318         for (i=0 ; i<MAX_MODELS ; i++)
1319         {
1320                 if (!sv.model_precache[i])
1321                 {
1322                         sv.model_precache[i] = s;
1323                         sv.models[i] = Mod_ForName (s, true, false, false);
1324                         return;
1325                 }
1326                 if (!strcmp(sv.model_precache[i], s))
1327                         return;
1328         }
1329         Host_Error ("PF_precache_model: overflow");
1330 }
1331
1332
1333 void PF_coredump (void)
1334 {
1335         ED_PrintEdicts ();
1336 }
1337
1338 void PF_traceon (void)
1339 {
1340         pr_trace = true;
1341 }
1342
1343 void PF_traceoff (void)
1344 {
1345         pr_trace = false;
1346 }
1347
1348 void PF_eprint (void)
1349 {
1350         ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1351 }
1352
1353 /*
1354 ===============
1355 PF_walkmove
1356
1357 float(float yaw, float dist) walkmove
1358 ===============
1359 */
1360 void PF_walkmove (void)
1361 {
1362         edict_t *ent;
1363         float   yaw, dist;
1364         vec3_t  move;
1365         mfunction_t     *oldf;
1366         int     oldself;
1367
1368         ent = PROG_TO_EDICT(pr_global_struct->self);
1369         if (ent == sv.edicts)
1370                 Host_Error("walkmove: can not modify world entity\n");
1371         if (ent->e->free)
1372                 Host_Error("walkmove: can not modify free entity\n");
1373         yaw = G_FLOAT(OFS_PARM0);
1374         dist = G_FLOAT(OFS_PARM1);
1375
1376         if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1377         {
1378                 G_FLOAT(OFS_RETURN) = 0;
1379                 return;
1380         }
1381
1382         yaw = yaw*M_PI*2 / 360;
1383
1384         move[0] = cos(yaw)*dist;
1385         move[1] = sin(yaw)*dist;
1386         move[2] = 0;
1387
1388 // save program state, because SV_movestep may call other progs
1389         oldf = pr_xfunction;
1390         oldself = pr_global_struct->self;
1391
1392         G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1393
1394
1395 // restore program state
1396         pr_xfunction = oldf;
1397         pr_global_struct->self = oldself;
1398 }
1399
1400 /*
1401 ===============
1402 PF_droptofloor
1403
1404 void() droptofloor
1405 ===============
1406 */
1407 void PF_droptofloor (void)
1408 {
1409         edict_t         *ent;
1410         vec3_t          end;
1411         trace_t         trace;
1412
1413         ent = PROG_TO_EDICT(pr_global_struct->self);
1414         if (ent == sv.edicts)
1415                 Host_Error("droptofloor: can not modify world entity\n");
1416         if (ent->e->free)
1417                 Host_Error("droptofloor: can not modify free entity\n");
1418
1419         VectorCopy (ent->v->origin, end);
1420         end[2] -= 256;
1421
1422         trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1423
1424         if (trace.fraction == 1)
1425                 G_FLOAT(OFS_RETURN) = 0;
1426         else
1427         {
1428                 VectorCopy (trace.endpos, ent->v->origin);
1429                 SV_LinkEdict (ent, false);
1430                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1431                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1432                 G_FLOAT(OFS_RETURN) = 1;
1433                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1434                 ent->e->suspendedinairflag = true;
1435         }
1436 }
1437
1438 /*
1439 ===============
1440 PF_lightstyle
1441
1442 void(float style, string value) lightstyle
1443 ===============
1444 */
1445 void PF_lightstyle (void)
1446 {
1447         int             style;
1448         char    *val;
1449         client_t        *client;
1450         int                     j;
1451
1452         style = G_FLOAT(OFS_PARM0);
1453         val = G_STRING(OFS_PARM1);
1454
1455 // change the string in sv
1456         sv.lightstyles[style] = val;
1457
1458 // send message to all clients on this server
1459         if (sv.state != ss_active)
1460                 return;
1461
1462         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1463         {
1464                 if (client->netconnection)
1465                 {
1466                         MSG_WriteChar (&client->message, svc_lightstyle);
1467                         MSG_WriteChar (&client->message,style);
1468                         MSG_WriteString (&client->message, val);
1469                 }
1470         }
1471 }
1472
1473 void PF_rint (void)
1474 {
1475         float   f;
1476         f = G_FLOAT(OFS_PARM0);
1477         if (f > 0)
1478                 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1479         else
1480                 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1481 }
1482 void PF_floor (void)
1483 {
1484         G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1485 }
1486 void PF_ceil (void)
1487 {
1488         G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1489 }
1490
1491
1492 /*
1493 =============
1494 PF_checkbottom
1495 =============
1496 */
1497 void PF_checkbottom (void)
1498 {
1499         G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1500 }
1501
1502 /*
1503 =============
1504 PF_pointcontents
1505 =============
1506 */
1507 void PF_pointcontents (void)
1508 {
1509         G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1510 }
1511
1512 /*
1513 =============
1514 PF_nextent
1515
1516 entity nextent(entity)
1517 =============
1518 */
1519 void PF_nextent (void)
1520 {
1521         int             i;
1522         edict_t *ent;
1523
1524         i = G_EDICTNUM(OFS_PARM0);
1525         while (1)
1526         {
1527                 pr_xfunction->builtinsprofile++;
1528                 i++;
1529                 if (i == sv.num_edicts)
1530                 {
1531                         RETURN_EDICT(sv.edicts);
1532                         return;
1533                 }
1534                 ent = EDICT_NUM(i);
1535                 if (!ent->e->free)
1536                 {
1537                         RETURN_EDICT(ent);
1538                         return;
1539                 }
1540         }
1541 }
1542
1543 /*
1544 =============
1545 PF_aim
1546
1547 Pick a vector for the player to shoot along
1548 vector aim(entity, missilespeed)
1549 =============
1550 */
1551 void PF_aim (void)
1552 {
1553         edict_t *ent, *check, *bestent;
1554         vec3_t  start, dir, end, bestdir;
1555         int             i, j;
1556         trace_t tr;
1557         float   dist, bestdist;
1558         float   speed;
1559
1560         ent = G_EDICT(OFS_PARM0);
1561         if (ent == sv.edicts)
1562                 Host_Error("aim: can not use world entity\n");
1563         if (ent->e->free)
1564                 Host_Error("aim: can not use free entity\n");
1565         speed = G_FLOAT(OFS_PARM1);
1566
1567         VectorCopy (ent->v->origin, start);
1568         start[2] += 20;
1569
1570 // try sending a trace straight
1571         VectorCopy (pr_global_struct->v_forward, dir);
1572         VectorMA (start, 2048, dir, end);
1573         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1574         if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1575         && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1576         {
1577                 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1578                 return;
1579         }
1580
1581
1582 // try all possible entities
1583         VectorCopy (dir, bestdir);
1584         bestdist = sv_aim.value;
1585         bestent = NULL;
1586
1587         check = NEXT_EDICT(sv.edicts);
1588         for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1589         {
1590                 pr_xfunction->builtinsprofile++;
1591                 if (check->v->takedamage != DAMAGE_AIM)
1592                         continue;
1593                 if (check == ent)
1594                         continue;
1595                 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1596                         continue;       // don't aim at teammate
1597                 for (j=0 ; j<3 ; j++)
1598                         end[j] = check->v->origin[j]
1599                         + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1600                 VectorSubtract (end, start, dir);
1601                 VectorNormalize (dir);
1602                 dist = DotProduct (dir, pr_global_struct->v_forward);
1603                 if (dist < bestdist)
1604                         continue;       // to far to turn
1605                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1606                 if (tr.ent == check)
1607                 {       // can shoot at this one
1608                         bestdist = dist;
1609                         bestent = check;
1610                 }
1611         }
1612
1613         if (bestent)
1614         {
1615                 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1616                 dist = DotProduct (dir, pr_global_struct->v_forward);
1617                 VectorScale (pr_global_struct->v_forward, dist, end);
1618                 end[2] = dir[2];
1619                 VectorNormalize (end);
1620                 VectorCopy (end, G_VECTOR(OFS_RETURN));
1621         }
1622         else
1623         {
1624                 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1625         }
1626 }
1627
1628 /*
1629 ==============
1630 PF_changeyaw
1631
1632 This was a major timewaster in progs, so it was converted to C
1633 ==============
1634 */
1635 void PF_changeyaw (void)
1636 {
1637         edict_t         *ent;
1638         float           ideal, current, move, speed;
1639
1640         ent = PROG_TO_EDICT(pr_global_struct->self);
1641         if (ent == sv.edicts)
1642                 Host_Error("changeyaw: can not modify world entity\n");
1643         if (ent->e->free)
1644                 Host_Error("changeyaw: can not modify free entity\n");
1645         current = ANGLEMOD(ent->v->angles[1]);
1646         ideal = ent->v->ideal_yaw;
1647         speed = ent->v->yaw_speed;
1648
1649         if (current == ideal)
1650                 return;
1651         move = ideal - current;
1652         if (ideal > current)
1653         {
1654                 if (move >= 180)
1655                         move = move - 360;
1656         }
1657         else
1658         {
1659                 if (move <= -180)
1660                         move = move + 360;
1661         }
1662         if (move > 0)
1663         {
1664                 if (move > speed)
1665                         move = speed;
1666         }
1667         else
1668         {
1669                 if (move < -speed)
1670                         move = -speed;
1671         }
1672
1673         ent->v->angles[1] = ANGLEMOD (current + move);
1674 }
1675
1676 /*
1677 ==============
1678 PF_changepitch
1679 ==============
1680 */
1681 void PF_changepitch (void)
1682 {
1683         edict_t         *ent;
1684         float           ideal, current, move, speed;
1685         eval_t          *val;
1686
1687         ent = G_EDICT(OFS_PARM0);
1688         if (ent == sv.edicts)
1689                 Host_Error("changepitch: can not modify world entity\n");
1690         if (ent->e->free)
1691                 Host_Error("changepitch: can not modify free entity\n");
1692         current = ANGLEMOD( ent->v->angles[0] );
1693         if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1694                 ideal = val->_float;
1695         else
1696         {
1697                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1698                 return;
1699         }
1700         if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1701                 speed = val->_float;
1702         else
1703         {
1704                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1705                 return;
1706         }
1707
1708         if (current == ideal)
1709                 return;
1710         move = ideal - current;
1711         if (ideal > current)
1712         {
1713                 if (move >= 180)
1714                         move = move - 360;
1715         }
1716         else
1717         {
1718                 if (move <= -180)
1719                         move = move + 360;
1720         }
1721         if (move > 0)
1722         {
1723                 if (move > speed)
1724                         move = speed;
1725         }
1726         else
1727         {
1728                 if (move < -speed)
1729                         move = -speed;
1730         }
1731
1732         ent->v->angles[0] = ANGLEMOD (current + move);
1733 }
1734
1735 /*
1736 ===============================================================================
1737
1738 MESSAGE WRITING
1739
1740 ===============================================================================
1741 */
1742
1743 #define MSG_BROADCAST   0               // unreliable to all
1744 #define MSG_ONE                 1               // reliable to one (msg_entity)
1745 #define MSG_ALL                 2               // reliable to all
1746 #define MSG_INIT                3               // write to the init string
1747
1748 sizebuf_t *WriteDest (void)
1749 {
1750         int             entnum;
1751         int             dest;
1752         edict_t *ent;
1753
1754         dest = G_FLOAT(OFS_PARM0);
1755         switch (dest)
1756         {
1757         case MSG_BROADCAST:
1758                 return &sv.datagram;
1759
1760         case MSG_ONE:
1761                 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1762                 entnum = NUM_FOR_EDICT(ent);
1763                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1764                         Host_Error("WriteDest: tried to write to non-client\n");
1765                 return &svs.clients[entnum-1].message;
1766
1767         case MSG_ALL:
1768                 return &sv.reliable_datagram;
1769
1770         case MSG_INIT:
1771                 return &sv.signon;
1772
1773         default:
1774                 Host_Error ("WriteDest: bad destination");
1775                 break;
1776         }
1777
1778         return NULL;
1779 }
1780
1781 void PF_WriteByte (void)
1782 {
1783         MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1784 }
1785
1786 void PF_WriteChar (void)
1787 {
1788         MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1789 }
1790
1791 void PF_WriteShort (void)
1792 {
1793         MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1794 }
1795
1796 void PF_WriteLong (void)
1797 {
1798         MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1799 }
1800
1801 void PF_WriteAngle (void)
1802 {
1803         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1804 }
1805
1806 void PF_WriteCoord (void)
1807 {
1808         MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1809 }
1810
1811 void PF_WriteString (void)
1812 {
1813         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1814 }
1815
1816
1817 void PF_WriteEntity (void)
1818 {
1819         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1820 }
1821
1822 //=============================================================================
1823
1824 void PF_makestatic (void)
1825 {
1826         edict_t *ent;
1827         int i, large;
1828
1829         ent = G_EDICT(OFS_PARM0);
1830         if (ent == sv.edicts)
1831                 Host_Error("makestatic: can not modify world entity\n");
1832         if (ent->e->free)
1833                 Host_Error("makestatic: can not modify free entity\n");
1834
1835         large = false;
1836         if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1837                 large = true;
1838
1839         if (large)
1840         {
1841                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1842                 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1843                 MSG_WriteShort (&sv.signon, ent->v->frame);
1844         }
1845         else
1846         {
1847                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1848                 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1849                 MSG_WriteByte (&sv.signon, ent->v->frame);
1850         }
1851
1852         MSG_WriteByte (&sv.signon, ent->v->colormap);
1853         MSG_WriteByte (&sv.signon, ent->v->skin);
1854         for (i=0 ; i<3 ; i++)
1855         {
1856                 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1857                 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1858         }
1859
1860 // throw the entity away now
1861         ED_Free (ent);
1862 }
1863
1864 //=============================================================================
1865
1866 /*
1867 ==============
1868 PF_setspawnparms
1869 ==============
1870 */
1871 void PF_setspawnparms (void)
1872 {
1873         edict_t *ent;
1874         int             i;
1875         client_t        *client;
1876
1877         ent = G_EDICT(OFS_PARM0);
1878         i = NUM_FOR_EDICT(ent);
1879         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1880         {
1881                 Con_Printf("tried to setspawnparms on a non-client\n");
1882                 return;
1883         }
1884
1885         // copy spawn parms out of the client_t
1886         client = svs.clients + i-1;
1887         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1888                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1889 }
1890
1891 /*
1892 ==============
1893 PF_changelevel
1894 ==============
1895 */
1896 void PF_changelevel (void)
1897 {
1898         char    *s;
1899
1900 // make sure we don't issue two changelevels
1901         if (svs.changelevel_issued)
1902                 return;
1903         svs.changelevel_issued = true;
1904
1905         s = G_STRING(OFS_PARM0);
1906         Cbuf_AddText (va("changelevel %s\n",s));
1907 }
1908
1909 void PF_sin (void)
1910 {
1911         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1912 }
1913
1914 void PF_cos (void)
1915 {
1916         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1917 }
1918
1919 void PF_sqrt (void)
1920 {
1921         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1922 }
1923
1924 /*
1925 =================
1926 PF_RandomVec
1927
1928 Returns a vector of length < 1
1929
1930 randomvec()
1931 =================
1932 */
1933 void PF_randomvec (void)
1934 {
1935         vec3_t          temp;
1936         do
1937         {
1938                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1939                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1940                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1941         }
1942         while (DotProduct(temp, temp) >= 1);
1943         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1944 }
1945
1946 /*
1947 =================
1948 PF_GetLight
1949
1950 Returns a color vector indicating the lighting at the requested point.
1951
1952 (Internal Operation note: actually measures the light beneath the point, just like
1953                           the model lighting on the client)
1954
1955 getlight(vector)
1956 =================
1957 */
1958 void PF_GetLight (void)
1959 {
1960         vec3_t ambientcolor, diffusecolor, diffusenormal;
1961         vec_t *p;
1962         p = G_VECTOR(OFS_PARM0);
1963         VectorClear(ambientcolor);
1964         VectorClear(diffusecolor);
1965         VectorClear(diffusenormal);
1966         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1967                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1968         VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1969 }
1970
1971 #define MAX_QC_CVARS 128
1972 cvar_t qc_cvar[MAX_QC_CVARS];
1973 int currentqc_cvar;
1974
1975 void PF_registercvar (void)
1976 {
1977         char *name, *value;
1978         cvar_t *variable;
1979         name = G_STRING(OFS_PARM0);
1980         value = G_STRING(OFS_PARM1);
1981         G_FLOAT(OFS_RETURN) = 0;
1982 // first check to see if it has already been defined
1983         if (Cvar_FindVar (name))
1984                 return;
1985
1986 // check for overlap with a command
1987         if (Cmd_Exists (name))
1988         {
1989                 Con_Printf ("PF_registercvar: %s is a command\n", name);
1990                 return;
1991         }
1992
1993         if (currentqc_cvar >= MAX_QC_CVARS)
1994                 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1995
1996 // copy the name and value
1997         variable = &qc_cvar[currentqc_cvar++];
1998         variable->name = Z_Malloc (strlen(name)+1);
1999         strcpy (variable->name, name);
2000         variable->string = Z_Malloc (strlen(value)+1);
2001         strcpy (variable->string, value);
2002         variable->value = atof (value);
2003
2004         Cvar_RegisterVariable(variable);
2005         G_FLOAT(OFS_RETURN) = 1; // success
2006 }
2007
2008 /*
2009 =================
2010 PF_min
2011
2012 returns the minimum of two supplied floats
2013
2014 min(a, b)
2015 =================
2016 */
2017 void PF_min (void)
2018 {
2019         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2020         if (pr_argc == 2)
2021                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2022         else if (pr_argc >= 3)
2023         {
2024                 int i;
2025                 float f = G_FLOAT(OFS_PARM0);
2026                 for (i = 1;i < pr_argc;i++)
2027                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
2028                                 f = G_FLOAT((OFS_PARM0+i*3));
2029                 G_FLOAT(OFS_RETURN) = f;
2030         }
2031         else
2032                 Host_Error("min: must supply at least 2 floats\n");
2033 }
2034
2035 /*
2036 =================
2037 PF_max
2038
2039 returns the maximum of two supplied floats
2040
2041 max(a, b)
2042 =================
2043 */
2044 void PF_max (void)
2045 {
2046         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2047         if (pr_argc == 2)
2048                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2049         else if (pr_argc >= 3)
2050         {
2051                 int i;
2052                 float f = G_FLOAT(OFS_PARM0);
2053                 for (i = 1;i < pr_argc;i++)
2054                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
2055                                 f = G_FLOAT((OFS_PARM0+i*3));
2056                 G_FLOAT(OFS_RETURN) = f;
2057         }
2058         else
2059                 Host_Error("max: must supply at least 2 floats\n");
2060 }
2061
2062 /*
2063 =================
2064 PF_bound
2065
2066 returns number bounded by supplied range
2067
2068 min(min, value, max)
2069 =================
2070 */
2071 void PF_bound (void)
2072 {
2073         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2074 }
2075
2076 /*
2077 =================
2078 PF_pow
2079
2080 returns a raised to power b
2081
2082 pow(a, b)
2083 =================
2084 */
2085 void PF_pow (void)
2086 {
2087         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2088 }
2089
2090 /*
2091 =================
2092 PF_copyentity
2093
2094 copies data from one entity to another
2095
2096 copyentity(src, dst)
2097 =================
2098 */
2099 void PF_copyentity (void)
2100 {
2101         edict_t *in, *out;
2102         in = G_EDICT(OFS_PARM0);
2103         if (in == sv.edicts)
2104                 Host_Error("copyentity: can not read world entity\n");
2105         if (in->e->free)
2106                 Host_Error("copyentity: can not read free entity\n");
2107         out = G_EDICT(OFS_PARM1);
2108         if (out == sv.edicts)
2109                 Host_Error("copyentity: can not modify world entity\n");
2110         if (out->e->free)
2111                 Host_Error("copyentity: can not modify free entity\n");
2112         memcpy(out->v, in->v, progs->entityfields * 4);
2113 }
2114
2115 /*
2116 =================
2117 PF_setcolor
2118
2119 sets the color of a client and broadcasts the update to all connected clients
2120
2121 setcolor(clientent, value)
2122 =================
2123 */
2124 void PF_setcolor (void)
2125 {
2126         client_t *client;
2127         int entnum, i;
2128         eval_t *val;
2129
2130         entnum = G_EDICTNUM(OFS_PARM0);
2131         i = G_FLOAT(OFS_PARM1);
2132
2133         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2134         {
2135                 Con_Printf ("tried to setcolor a non-client\n");
2136                 return;
2137         }
2138
2139         client = svs.clients + entnum-1;
2140         if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2141                 val->_float = i;
2142         client->colors = i;
2143         client->old_colors = i;
2144         client->edict->v->team = (i & 15) + 1;
2145
2146         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2147         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2148         MSG_WriteByte (&sv.reliable_datagram, i);
2149 }
2150
2151 /*
2152 =================
2153 PF_effect
2154
2155 effect(origin, modelname, startframe, framecount, framerate)
2156 =================
2157 */
2158 void PF_effect (void)
2159 {
2160         char *s;
2161         s = G_STRING(OFS_PARM1);
2162         if (!s || !s[0])
2163                 Host_Error("effect: no model specified\n");
2164
2165         SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2166 }
2167
2168 void PF_te_blood (void)
2169 {
2170         if (G_FLOAT(OFS_PARM2) < 1)
2171                 return;
2172         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2173         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2174         // origin
2175         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2176         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2177         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2178         // velocity
2179         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2180         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2181         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2182         // count
2183         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2184 }
2185
2186 void PF_te_bloodshower (void)
2187 {
2188         if (G_FLOAT(OFS_PARM3) < 1)
2189                 return;
2190         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2191         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2192         // min
2193         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2194         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2195         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2196         // max
2197         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2198         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2199         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2200         // speed
2201         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2202         // count
2203         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2204 }
2205
2206 void PF_te_explosionrgb (void)
2207 {
2208         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2209         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2210         // origin
2211         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2212         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2213         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2214         // color
2215         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2216         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2217         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2218 }
2219
2220 void PF_te_particlecube (void)
2221 {
2222         if (G_FLOAT(OFS_PARM3) < 1)
2223                 return;
2224         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2225         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2226         // min
2227         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2228         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2229         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2230         // max
2231         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2232         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2233         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2234         // velocity
2235         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2236         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2237         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2238         // count
2239         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2240         // color
2241         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2242         // gravity true/false
2243         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2244         // randomvel
2245         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2246 }
2247
2248 void PF_te_particlerain (void)
2249 {
2250         if (G_FLOAT(OFS_PARM3) < 1)
2251                 return;
2252         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2253         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2254         // min
2255         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2256         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2257         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2258         // max
2259         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2260         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2261         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2262         // velocity
2263         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2264         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2265         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2266         // count
2267         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2268         // color
2269         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2270 }
2271
2272 void PF_te_particlesnow (void)
2273 {
2274         if (G_FLOAT(OFS_PARM3) < 1)
2275                 return;
2276         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2277         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2278         // min
2279         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2280         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2281         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2282         // max
2283         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2284         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2285         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2286         // velocity
2287         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2288         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2289         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2290         // count
2291         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2292         // color
2293         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2294 }
2295
2296 void PF_te_spark (void)
2297 {
2298         if (G_FLOAT(OFS_PARM2) < 1)
2299                 return;
2300         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2301         MSG_WriteByte(&sv.datagram, TE_SPARK);
2302         // origin
2303         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2304         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2305         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2306         // velocity
2307         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2308         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2309         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2310         // count
2311         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2312 }
2313
2314 void PF_te_gunshotquad (void)
2315 {
2316         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2317         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2318         // origin
2319         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2320         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2321         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2322 }
2323
2324 void PF_te_spikequad (void)
2325 {
2326         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2327         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2328         // origin
2329         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2330         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2331         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2332 }
2333
2334 void PF_te_superspikequad (void)
2335 {
2336         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2337         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2338         // origin
2339         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2340         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2341         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2342 }
2343
2344 void PF_te_explosionquad (void)
2345 {
2346         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2347         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2348         // origin
2349         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2350         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2351         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2352 }
2353
2354 void PF_te_smallflash (void)
2355 {
2356         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2357         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2358         // origin
2359         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2360         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2361         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2362 }
2363
2364 void PF_te_customflash (void)
2365 {
2366         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2367                 return;
2368         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2369         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2370         // origin
2371         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2372         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2373         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2374         // radius
2375         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2376         // lifetime
2377         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2378         // color
2379         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2380         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2381         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2382 }
2383
2384 void PF_te_gunshot (void)
2385 {
2386         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2387         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2388         // origin
2389         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2390         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2391         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2392 }
2393
2394 void PF_te_spike (void)
2395 {
2396         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2398         // origin
2399         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2400         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2401         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2402 }
2403
2404 void PF_te_superspike (void)
2405 {
2406         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2407         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2408         // origin
2409         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2410         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2411         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2412 }
2413
2414 void PF_te_explosion (void)
2415 {
2416         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2417         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2418         // origin
2419         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2420         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2421         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2422 }
2423
2424 void PF_te_tarexplosion (void)
2425 {
2426         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2427         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2428         // origin
2429         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2430         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2431         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2432 }
2433
2434 void PF_te_wizspike (void)
2435 {
2436         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2437         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2438         // origin
2439         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2440         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2441         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2442 }
2443
2444 void PF_te_knightspike (void)
2445 {
2446         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2447         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2448         // origin
2449         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2450         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2451         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2452 }
2453
2454 void PF_te_lavasplash (void)
2455 {
2456         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2457         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2458         // origin
2459         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2460         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2461         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2462 }
2463
2464 void PF_te_teleport (void)
2465 {
2466         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2467         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2468         // origin
2469         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2470         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2471         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2472 }
2473
2474 void PF_te_explosion2 (void)
2475 {
2476         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2477         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2478         // origin
2479         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2480         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2481         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2482         // color
2483         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2484 }
2485
2486 void PF_te_lightning1 (void)
2487 {
2488         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2489         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2490         // owner entity
2491         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2492         // start
2493         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2494         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2495         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2496         // end
2497         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2498         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2499         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2500 }
2501
2502 void PF_te_lightning2 (void)
2503 {
2504         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2505         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2506         // owner entity
2507         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2508         // start
2509         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2510         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2511         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2512         // end
2513         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2514         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2515         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2516 }
2517
2518 void PF_te_lightning3 (void)
2519 {
2520         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2521         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2522         // owner entity
2523         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2524         // start
2525         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2526         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2527         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2528         // end
2529         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2530         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2531         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2532 }
2533
2534 void PF_te_beam (void)
2535 {
2536         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2537         MSG_WriteByte(&sv.datagram, TE_BEAM);
2538         // owner entity
2539         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2540         // start
2541         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2542         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2543         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2544         // end
2545         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2546         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2547         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2548 }
2549
2550 void PF_te_plasmaburn (void)
2551 {
2552         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2553         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2554         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2555         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2556         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2557 }
2558
2559 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2560 {
2561         int i, j;
2562         vec3_t v1, clipplanenormal, normal;
2563         vec_t clipplanedist, clipdist;
2564         VectorCopy(p, out);
2565         if (surf->flags & SURF_PLANEBACK)
2566                 VectorNegate(surf->plane->normal, normal);
2567         else
2568                 VectorCopy(surf->plane->normal, normal);
2569         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2570         {
2571                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2572                 VectorNormalizeFast(v1);
2573                 CrossProduct(v1, normal, clipplanenormal);
2574                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2575                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2576                 if (clipdist > 0)
2577                 {
2578                         clipdist = -clipdist;
2579                         VectorMA(out, clipdist, clipplanenormal, out);
2580                 }
2581         }
2582 }
2583
2584 static msurface_t *getsurface(edict_t *ed, int surfnum)
2585 {
2586         int modelindex;
2587         model_t *model;
2588         if (!ed || ed->e->free)
2589                 return NULL;
2590         modelindex = ed->v->modelindex;
2591         if (modelindex < 1 || modelindex >= MAX_MODELS)
2592                 return NULL;
2593         model = sv.models[modelindex];
2594         if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2595                 return NULL;
2596         return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2597 }
2598
2599
2600 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2601 void PF_getsurfacenumpoints(void)
2602 {
2603         msurface_t *surf;
2604         // return 0 if no such surface
2605         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2606         {
2607                 G_FLOAT(OFS_RETURN) = 0;
2608                 return;
2609         }
2610
2611         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2612 }
2613 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2614 void PF_getsurfacepoint(void)
2615 {
2616         edict_t *ed;
2617         msurface_t *surf;
2618         int pointnum;
2619         VectorClear(G_VECTOR(OFS_RETURN));
2620         ed = G_EDICT(OFS_PARM0);
2621         if (!ed || ed->e->free)
2622                 return;
2623         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2624                 return;
2625         pointnum = G_FLOAT(OFS_PARM2);
2626         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2627                 return;
2628         // FIXME: implement rotation/scaling
2629         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2630 }
2631 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2632 void PF_getsurfacenormal(void)
2633 {
2634         msurface_t *surf;
2635         VectorClear(G_VECTOR(OFS_RETURN));
2636         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2637                 return;
2638         // FIXME: implement rotation/scaling
2639         if (surf->flags & SURF_PLANEBACK)
2640                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2641         else
2642                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2643 }
2644 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2645 void PF_getsurfacetexture(void)
2646 {
2647         msurface_t *surf;
2648         G_INT(OFS_RETURN) = 0;
2649         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2650                 return;
2651         G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2652 }
2653 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2654 void PF_getsurfacenearpoint(void)
2655 {
2656         int surfnum, best, modelindex;
2657         vec3_t clipped, p;
2658         vec_t dist, bestdist;
2659         edict_t *ed;
2660         model_t *model;
2661         msurface_t *surf;
2662         vec_t *point;
2663         G_FLOAT(OFS_RETURN) = -1;
2664         ed = G_EDICT(OFS_PARM0);
2665         point = G_VECTOR(OFS_PARM1);
2666
2667         if (!ed || ed->e->free)
2668                 return;
2669         modelindex = ed->v->modelindex;
2670         if (modelindex < 1 || modelindex >= MAX_MODELS)
2671                 return;
2672         model = sv.models[modelindex];
2673         if (!model->brushq1.numsurfaces)
2674                 return;
2675
2676         // FIXME: implement rotation/scaling
2677         VectorSubtract(point, ed->v->origin, p);
2678         best = -1;
2679         bestdist = 1000000000;
2680         for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2681         {
2682                 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2683                 dist = PlaneDiff(p, surf->plane);
2684                 dist = dist * dist;
2685                 if (dist < bestdist)
2686                 {
2687                         clippointtosurface(surf, p, clipped);
2688                         VectorSubtract(clipped, p, clipped);
2689                         dist += DotProduct(clipped, clipped);
2690                         if (dist < bestdist)
2691                         {
2692                                 best = surfnum;
2693                                 bestdist = dist;
2694                         }
2695                 }
2696         }
2697         G_FLOAT(OFS_RETURN) = best;
2698 }
2699 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2700 void PF_getsurfaceclippedpoint(void)
2701 {
2702         edict_t *ed;
2703         msurface_t *surf;
2704         vec3_t p, out;
2705         VectorClear(G_VECTOR(OFS_RETURN));
2706         ed = G_EDICT(OFS_PARM0);
2707         if (!ed || ed->e->free)
2708                 return;
2709         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2710                 return;
2711         // FIXME: implement rotation/scaling
2712         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2713         clippointtosurface(surf, p, out);
2714         // FIXME: implement rotation/scaling
2715         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2716 }
2717
2718 #define MAX_PRFILES 256
2719
2720 qfile_t *pr_files[MAX_PRFILES];
2721
2722 void PR_Files_Init(void)
2723 {
2724         memset(pr_files, 0, sizeof(pr_files));
2725 }
2726
2727 void PR_Files_CloseAll(void)
2728 {
2729         int i;
2730         for (i = 0;i < MAX_PRFILES;i++)
2731         {
2732                 if (pr_files[i])
2733                         FS_Close(pr_files[i]);
2734                 pr_files[i] = NULL;
2735         }
2736 }
2737
2738 //float(string s) stof = #81; // get numerical value from a string
2739 void PF_stof(void)
2740 {
2741         char string[STRINGTEMP_LENGTH];
2742         PF_VarString(0, string, sizeof(string));
2743         G_FLOAT(OFS_RETURN) = atof(string);
2744 }
2745
2746 //float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
2747 void PF_fopen(void)
2748 {
2749         int filenum, mode;
2750         char *modestring, *filename;
2751         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2752                 if (pr_files[filenum] == NULL)
2753                         break;
2754         if (filenum >= MAX_PRFILES)
2755         {
2756                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2757                 G_FLOAT(OFS_RETURN) = -2;
2758                 return;
2759         }
2760         mode = G_FLOAT(OFS_PARM1);
2761         switch(mode)
2762         {
2763         case 0: // FILE_READ
2764                 modestring = "rb";
2765                 break;
2766         case 1: // FILE_APPEND
2767                 modestring = "ab";
2768                 break;
2769         case 2: // FILE_WRITE
2770                 modestring = "wb";
2771                 break;
2772         default:
2773                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2774                 G_FLOAT(OFS_RETURN) = -3;
2775                 return;
2776         }
2777         filename = G_STRING(OFS_PARM0);
2778         // .. is parent directory on many platforms
2779         // / is parent directory on Amiga
2780         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2781         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2782         if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2783         {
2784                 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2785                 G_FLOAT(OFS_RETURN) = -4;
2786                 return;
2787         }
2788         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2789         if (pr_files[filenum] == NULL)
2790                 G_FLOAT(OFS_RETURN) = -1;
2791         else
2792                 G_FLOAT(OFS_RETURN) = filenum;
2793 }
2794
2795 //void(float fhandle) fclose = #111; // closes a file
2796 void PF_fclose(void)
2797 {
2798         int filenum = G_FLOAT(OFS_PARM0);
2799         if (filenum < 0 || filenum >= MAX_PRFILES)
2800         {
2801                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2802                 return;
2803         }
2804         if (pr_files[filenum] == NULL)
2805         {
2806                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2807                 return;
2808         }
2809         FS_Close(pr_files[filenum]);
2810         pr_files[filenum] = NULL;
2811 }
2812
2813 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2814 void PF_fgets(void)
2815 {
2816         int c, end;
2817         static char string[STRINGTEMP_LENGTH];
2818         int filenum = G_FLOAT(OFS_PARM0);
2819         if (filenum < 0 || filenum >= MAX_PRFILES)
2820         {
2821                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2822                 return;
2823         }
2824         if (pr_files[filenum] == NULL)
2825         {
2826                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2827                 return;
2828         }
2829         end = 0;
2830         for (;;)
2831         {
2832                 c = FS_Getc(pr_files[filenum]);
2833                 if (c == '\r' || c == '\n' || c < 0)
2834                         break;
2835                 if (end < STRINGTEMP_LENGTH - 1)
2836                         string[end++] = c;
2837         }
2838         string[end] = 0;
2839         // remove \n following \r
2840         if (c == '\r')
2841                 c = FS_Getc(pr_files[filenum]);
2842         if (developer.integer)
2843                 Con_Printf("fgets: %s\n", string);
2844         if (c >= 0)
2845                 G_INT(OFS_RETURN) = PR_SetString(string);
2846         else
2847                 G_INT(OFS_RETURN) = 0;
2848 }
2849
2850 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2851 void PF_fputs(void)
2852 {
2853         int stringlength;
2854         char string[STRINGTEMP_LENGTH];
2855         int filenum = G_FLOAT(OFS_PARM0);
2856         if (filenum < 0 || filenum >= MAX_PRFILES)
2857         {
2858                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2859                 return;
2860         }
2861         if (pr_files[filenum] == NULL)
2862         {
2863                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2864                 return;
2865         }
2866         PF_VarString(1, string, sizeof(string));
2867         if ((stringlength = strlen(string)))
2868                 FS_Write(pr_files[filenum], string, stringlength);
2869         if (developer.integer)
2870                 Con_Printf("fputs: %s\n", string);
2871 }
2872
2873 //float(string s) strlen = #114; // returns how many characters are in a string
2874 void PF_strlen(void)
2875 {
2876         char *s;
2877         s = G_STRING(OFS_PARM0);
2878         if (s)
2879                 G_FLOAT(OFS_RETURN) = strlen(s);
2880         else
2881                 G_FLOAT(OFS_RETURN) = 0;
2882 }
2883
2884 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2885 void PF_strcat(void)
2886 {
2887         char *s = PR_GetTempString();
2888         PF_VarString(0, s, STRINGTEMP_LENGTH);
2889         G_INT(OFS_RETURN) = PR_SetString(s);
2890 }
2891
2892 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2893 void PF_substring(void)
2894 {
2895         int i, start, length;
2896         char *s, *string = PR_GetTempString();
2897         s = G_STRING(OFS_PARM0);
2898         start = G_FLOAT(OFS_PARM1);
2899         length = G_FLOAT(OFS_PARM2);
2900         if (!s)
2901                 s = "";
2902         for (i = 0;i < start && *s;i++, s++);
2903         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2904                 string[i] = *s;
2905         string[i] = 0;
2906         G_INT(OFS_RETURN) = PR_SetString(string);
2907 }
2908
2909 //vector(string s) stov = #117; // returns vector value from a string
2910 void PF_stov(void)
2911 {
2912         char string[STRINGTEMP_LENGTH];
2913         PF_VarString(0, string, sizeof(string));
2914         Math_atov(string, G_VECTOR(OFS_RETURN));
2915 }
2916
2917 //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
2918 void PF_strzone(void)
2919 {
2920         char *in, *out;
2921         in = G_STRING(OFS_PARM0);
2922         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2923         strcpy(out, in);
2924         G_INT(OFS_RETURN) = PR_SetString(out);
2925 }
2926
2927 //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
2928 void PF_strunzone(void)
2929 {
2930         Mem_Free(G_STRING(OFS_PARM0));
2931 }
2932
2933 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2934 //this function originally written by KrimZon, made shorter by LordHavoc
2935 void PF_clientcommand (void)
2936 {
2937         client_t *temp_client;
2938         int i;
2939
2940         //find client for this entity
2941         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2942         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2943         {
2944                 Con_Printf("PF_clientcommand: entity is not a client");
2945                 return;
2946         }
2947
2948         temp_client = host_client;
2949         host_client = svs.clients + i;
2950         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2951         host_client = temp_client;
2952 }
2953
2954 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2955 //this function originally written by KrimZon, made shorter by LordHavoc
2956 char **tokens = NULL;
2957 int    max_tokens, num_tokens = 0;
2958 void PF_tokenize (void)
2959 {
2960         const char *p;
2961         char *str;
2962         str = G_STRING(OFS_PARM0);
2963
2964         if (tokens != NULL)
2965         {
2966                 int i;
2967                 for (i=0;i<num_tokens;i++)
2968                         Z_Free(tokens[i]);
2969                 Z_Free(tokens);
2970                 num_tokens = 0;
2971         }
2972
2973         tokens = Z_Malloc(strlen(str) * sizeof(char *));
2974         max_tokens = strlen(str);
2975
2976         for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2977         {
2978                 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2979                 strcpy(tokens[num_tokens], com_token);
2980         }
2981
2982         G_FLOAT(OFS_RETURN) = num_tokens;
2983 }
2984
2985 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2986 //this function originally written by KrimZon, made shorter by LordHavoc
2987 void PF_argv (void)
2988 {
2989         int token_num = G_FLOAT(OFS_PARM0);
2990         if (token_num >= 0 && token_num < num_tokens)
2991                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2992         else
2993                 G_INT(OFS_RETURN) = PR_SetString("");
2994 }
2995
2996 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
2997 void PF_setattachment (void)
2998 {
2999         edict_t *e = G_EDICT(OFS_PARM0);
3000         edict_t *tagentity = G_EDICT(OFS_PARM1);
3001         char *tagname = G_STRING(OFS_PARM2);
3002         eval_t *v;
3003         int i, modelindex;
3004         model_t *model;
3005
3006         if (e == sv.edicts)
3007                 Host_Error("setattachment: can not modify world entity\n");
3008         if (e->e->free)
3009                 Host_Error("setattachment: can not modify free entity\n");
3010
3011         if (tagentity == NULL)
3012                 tagentity = sv.edicts;
3013
3014         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3015         if (v)
3016                 v->edict = EDICT_TO_PROG(tagentity);
3017
3018         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3019         if (v)
3020                 v->_float = 0;
3021         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3022         {
3023                 modelindex = (int)tagentity->v->modelindex;
3024                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3025                 {
3026                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3027                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3028                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3029                                                 v->_float = i + 1;
3030                         if (v->_float == 0 && model->alias.aliasnum_tags)
3031                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3032                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3033                                                 v->_float = i + 1;
3034                         if (v->_float == 0)
3035                                 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
3036                 }
3037                 else
3038                         Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
3039         }
3040 }
3041
3042
3043 builtin_t pr_builtin[] =
3044 {
3045 NULL,                                           // #0
3046 PF_makevectors,                         // #1 void(entity e) makevectors
3047 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3048 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3049 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3050 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3051 PF_break,                                       // #6 void() break
3052 PF_random,                                      // #7 float() random
3053 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3054 PF_normalize,                           // #9 vector(vector v) normalize
3055 PF_error,                                       // #10 void(string e) error
3056 PF_objerror,                            // #11 void(string e) objerror
3057 PF_vlen,                                        // #12 float(vector v) vlen
3058 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3059 PF_Spawn,                                       // #14 entity() spawn
3060 PF_Remove,                                      // #15 void(entity e) remove
3061 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3062 PF_checkclient,                         // #17 entity() clientlist
3063 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3064 PF_precache_sound,                      // #19 void(string s) precache_sound
3065 PF_precache_model,                      // #20 void(string s) precache_model
3066 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3067 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3068 PF_bprint,                                      // #23 void(string s) bprint
3069 PF_sprint,                                      // #24 void(entity client, string s) sprint
3070 PF_dprint,                                      // #25 void(string s) dprint
3071 PF_ftos,                                        // #26 void(string s) ftos
3072 PF_vtos,                                        // #27 void(string s) vtos
3073 PF_coredump,                            // #28 void() coredump
3074 PF_traceon,                                     // #29 void() traceon
3075 PF_traceoff,                            // #30 void() traceoff
3076 PF_eprint,                                      // #31 void(entity e) eprint
3077 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3078 NULL,                                           // #33
3079 PF_droptofloor,                         // #34 float() droptofloor
3080 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3081 PF_rint,                                        // #36 float(float v) rint
3082 PF_floor,                                       // #37 float(float v) floor
3083 PF_ceil,                                        // #38 float(float v) ceil
3084 NULL,                                           // #39
3085 PF_checkbottom,                         // #40 float(entity e) checkbottom
3086 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3087 NULL,                                           // #42
3088 PF_fabs,                                        // #43 float(float f) fabs
3089 PF_aim,                                         // #44 vector(entity e, float speed) aim
3090 PF_cvar,                                        // #45 float(string s) cvar
3091 PF_localcmd,                            // #46 void(string s) localcmd
3092 PF_nextent,                                     // #47 entity(entity e) nextent
3093 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3094 PF_changeyaw,                           // #49 void() ChangeYaw
3095 NULL,                                           // #50
3096 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3097 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3098 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3099 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3100 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3101 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3102 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3103 PF_WriteString,                         // #58 void(float to, string s) WriteString
3104 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3105 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3106 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3107 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3108 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3109 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3110 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3111 NULL,                                           // #66
3112 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3113 PF_precache_file,                       // #68 string(string s) precache_file
3114 PF_makestatic,                          // #69 void(entity e) makestatic
3115 PF_changelevel,                         // #70 void(string s) changelevel
3116 NULL,                                           // #71
3117 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3118 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3119 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3120 PF_precache_model,                      // #75 string(string s) precache_model2
3121 PF_precache_sound,                      // #76 string(string s) precache_sound2
3122 PF_precache_file,                       // #77 string(string s) precache_file2
3123 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3124 NULL,                                           // #79
3125 NULL,                                           // #80
3126 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3127 NULL,                                           // #82
3128 NULL,                                           // #83
3129 NULL,                                           // #84
3130 NULL,                                           // #85
3131 NULL,                                           // #86
3132 NULL,                                           // #87
3133 NULL,                                           // #88
3134 NULL,                                           // #89
3135 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3136 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3137 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3138 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3139 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3140 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3141 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3142 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3143 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3144 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3145 NULL,                                           // #100
3146 NULL,                                           // #101
3147 NULL,                                           // #102
3148 NULL,                                           // #103
3149 NULL,                                           // #104
3150 NULL,                                           // #105
3151 NULL,                                           // #106
3152 NULL,                                           // #107
3153 NULL,                                           // #108
3154 NULL,                                           // #109
3155 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3156 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3157 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3158 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3159 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3160 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3161 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3162 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3163 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3164 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3165 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3166 a a a a a a a a                         // #120-199
3167 a a a a a a a a a a                     // #200-299
3168 a a a a a a a a a a                     // #300-399
3169 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3170 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3171 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3172 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3173 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3174 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3175 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3176 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3177 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3178 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3179 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3180 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3181 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3182 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3183 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3184 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3185 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3186 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3187 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3188 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3189 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3190 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3191 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3192 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3193 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3194 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3195 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3196 PF_te_explosion2,                       // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3197 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3198 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3199 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3200 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3201 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3202 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3203 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3204 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3205 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3206 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3207 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3208 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3209 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3210 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3211 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3212 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3213 NULL,                                           // #444
3214 NULL,                                           // #445
3215 NULL,                                           // #446
3216 NULL,                                           // #447
3217 NULL,                                           // #448
3218 NULL,                                           // #449
3219 a a a a a                                       // #450-499 (LordHavoc)
3220 };
3221
3222 builtin_t *pr_builtins = pr_builtin;
3223 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3224
3225 void PR_Cmd_Init(void)
3226 {
3227         pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3228         PR_Files_Init();
3229 }
3230
3231 void PR_Cmd_Reset(void)
3232 {
3233         Mem_EmptyPool(pr_strings_mempool);
3234         PR_Files_CloseAll();
3235 }
3236