]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
ClearAllStates cleared the key states twice in vid_wgl.c, and vid_glx.c didn't do...
[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         // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1131         if (ed->e->free && developer.integer)
1132                 Con_Printf("remove: tried to remove an entity that was already removed\n");
1133         ED_Free (ed);
1134 }
1135
1136
1137 // entity (entity start, .string field, string match) find = #5;
1138 void PF_Find (void)
1139 {
1140         int             e;
1141         int             f;
1142         char    *s, *t;
1143         edict_t *ed;
1144
1145         e = G_EDICTNUM(OFS_PARM0);
1146         f = G_INT(OFS_PARM1);
1147         s = G_STRING(OFS_PARM2);
1148         if (!s || !s[0])
1149         {
1150                 RETURN_EDICT(sv.edicts);
1151                 return;
1152         }
1153
1154         for (e++ ; e < sv.num_edicts ; e++)
1155         {
1156                 pr_xfunction->builtinsprofile++;
1157                 ed = EDICT_NUM(e);
1158                 if (ed->e->free)
1159                         continue;
1160                 t = E_STRING(ed,f);
1161                 if (!t)
1162                         continue;
1163                 if (!strcmp(t,s))
1164                 {
1165                         RETURN_EDICT(ed);
1166                         return;
1167                 }
1168         }
1169
1170         RETURN_EDICT(sv.edicts);
1171 }
1172
1173 // LordHavoc: added this for searching float, int, and entity reference fields
1174 void PF_FindFloat (void)
1175 {
1176         int             e;
1177         int             f;
1178         float   s;
1179         edict_t *ed;
1180
1181         e = G_EDICTNUM(OFS_PARM0);
1182         f = G_INT(OFS_PARM1);
1183         s = G_FLOAT(OFS_PARM2);
1184
1185         for (e++ ; e < sv.num_edicts ; e++)
1186         {
1187                 pr_xfunction->builtinsprofile++;
1188                 ed = EDICT_NUM(e);
1189                 if (ed->e->free)
1190                         continue;
1191                 if (E_FLOAT(ed,f) == s)
1192                 {
1193                         RETURN_EDICT(ed);
1194                         return;
1195                 }
1196         }
1197
1198         RETURN_EDICT(sv.edicts);
1199 }
1200
1201 // chained search for strings in entity fields
1202 // entity(.string field, string match) findchain = #402;
1203 void PF_findchain (void)
1204 {
1205         int             i;
1206         int             f;
1207         char    *s, *t;
1208         edict_t *ent, *chain;
1209
1210         chain = (edict_t *)sv.edicts;
1211
1212         f = G_INT(OFS_PARM0);
1213         s = G_STRING(OFS_PARM1);
1214         if (!s || !s[0])
1215         {
1216                 RETURN_EDICT(sv.edicts);
1217                 return;
1218         }
1219
1220         ent = NEXT_EDICT(sv.edicts);
1221         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1222         {
1223                 pr_xfunction->builtinsprofile++;
1224                 if (ent->e->free)
1225                         continue;
1226                 t = E_STRING(ent,f);
1227                 if (!t)
1228                         continue;
1229                 if (strcmp(t,s))
1230                         continue;
1231
1232                 ent->v->chain = EDICT_TO_PROG(chain);
1233                 chain = ent;
1234         }
1235
1236         RETURN_EDICT(chain);
1237 }
1238
1239 // LordHavoc: chained search for float, int, and entity reference fields
1240 // entity(.string field, float match) findchainfloat = #403;
1241 void PF_findchainfloat (void)
1242 {
1243         int             i;
1244         int             f;
1245         float   s;
1246         edict_t *ent, *chain;
1247
1248         chain = (edict_t *)sv.edicts;
1249
1250         f = G_INT(OFS_PARM0);
1251         s = G_FLOAT(OFS_PARM1);
1252
1253         ent = NEXT_EDICT(sv.edicts);
1254         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1255         {
1256                 pr_xfunction->builtinsprofile++;
1257                 if (ent->e->free)
1258                         continue;
1259                 if (E_FLOAT(ent,f) != s)
1260                         continue;
1261
1262                 ent->v->chain = EDICT_TO_PROG(chain);
1263                 chain = ent;
1264         }
1265
1266         RETURN_EDICT(chain);
1267 }
1268
1269 void PR_CheckEmptyString (char *s)
1270 {
1271         if (s[0] <= ' ')
1272                 Host_Error ("Bad string");
1273 }
1274
1275 void PF_precache_file (void)
1276 {       // precache_file is only used to copy files with qcc, it does nothing
1277         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1278 }
1279
1280 void PF_precache_sound (void)
1281 {
1282         char    *s;
1283         int             i;
1284
1285         if (sv.state != ss_loading)
1286                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1287
1288         s = G_STRING(OFS_PARM0);
1289         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1290         PR_CheckEmptyString (s);
1291
1292         for (i=0 ; i<MAX_SOUNDS ; i++)
1293         {
1294                 if (!sv.sound_precache[i])
1295                 {
1296                         sv.sound_precache[i] = s;
1297                         return;
1298                 }
1299                 if (!strcmp(sv.sound_precache[i], s))
1300                         return;
1301         }
1302         Host_Error ("PF_precache_sound: overflow");
1303 }
1304
1305 void PF_precache_model (void)
1306 {
1307         char    *s;
1308         int             i;
1309
1310         if (sv.state != ss_loading)
1311                 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1312
1313         s = G_STRING(OFS_PARM0);
1314         if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1315                 return;
1316         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1317         PR_CheckEmptyString (s);
1318
1319         for (i=0 ; i<MAX_MODELS ; i++)
1320         {
1321                 if (!sv.model_precache[i])
1322                 {
1323                         sv.model_precache[i] = s;
1324                         sv.models[i] = Mod_ForName (s, true, false, false);
1325                         return;
1326                 }
1327                 if (!strcmp(sv.model_precache[i], s))
1328                         return;
1329         }
1330         Host_Error ("PF_precache_model: overflow");
1331 }
1332
1333
1334 void PF_coredump (void)
1335 {
1336         ED_PrintEdicts ();
1337 }
1338
1339 void PF_traceon (void)
1340 {
1341         pr_trace = true;
1342 }
1343
1344 void PF_traceoff (void)
1345 {
1346         pr_trace = false;
1347 }
1348
1349 void PF_eprint (void)
1350 {
1351         ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1352 }
1353
1354 /*
1355 ===============
1356 PF_walkmove
1357
1358 float(float yaw, float dist) walkmove
1359 ===============
1360 */
1361 void PF_walkmove (void)
1362 {
1363         edict_t *ent;
1364         float   yaw, dist;
1365         vec3_t  move;
1366         mfunction_t     *oldf;
1367         int     oldself;
1368
1369         ent = PROG_TO_EDICT(pr_global_struct->self);
1370         if (ent == sv.edicts)
1371                 Host_Error("walkmove: can not modify world entity\n");
1372         if (ent->e->free)
1373                 Host_Error("walkmove: can not modify free entity\n");
1374         yaw = G_FLOAT(OFS_PARM0);
1375         dist = G_FLOAT(OFS_PARM1);
1376
1377         if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1378         {
1379                 G_FLOAT(OFS_RETURN) = 0;
1380                 return;
1381         }
1382
1383         yaw = yaw*M_PI*2 / 360;
1384
1385         move[0] = cos(yaw)*dist;
1386         move[1] = sin(yaw)*dist;
1387         move[2] = 0;
1388
1389 // save program state, because SV_movestep may call other progs
1390         oldf = pr_xfunction;
1391         oldself = pr_global_struct->self;
1392
1393         G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1394
1395
1396 // restore program state
1397         pr_xfunction = oldf;
1398         pr_global_struct->self = oldself;
1399 }
1400
1401 /*
1402 ===============
1403 PF_droptofloor
1404
1405 void() droptofloor
1406 ===============
1407 */
1408 void PF_droptofloor (void)
1409 {
1410         edict_t         *ent;
1411         vec3_t          end;
1412         trace_t         trace;
1413
1414         ent = PROG_TO_EDICT(pr_global_struct->self);
1415         if (ent == sv.edicts)
1416                 Host_Error("droptofloor: can not modify world entity\n");
1417         if (ent->e->free)
1418                 Host_Error("droptofloor: can not modify free entity\n");
1419
1420         VectorCopy (ent->v->origin, end);
1421         end[2] -= 256;
1422
1423         trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1424
1425         if (trace.fraction == 1)
1426                 G_FLOAT(OFS_RETURN) = 0;
1427         else
1428         {
1429                 VectorCopy (trace.endpos, ent->v->origin);
1430                 SV_LinkEdict (ent, false);
1431                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1432                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1433                 G_FLOAT(OFS_RETURN) = 1;
1434                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1435                 ent->e->suspendedinairflag = true;
1436         }
1437 }
1438
1439 /*
1440 ===============
1441 PF_lightstyle
1442
1443 void(float style, string value) lightstyle
1444 ===============
1445 */
1446 void PF_lightstyle (void)
1447 {
1448         int             style;
1449         char    *val;
1450         client_t        *client;
1451         int                     j;
1452
1453         style = G_FLOAT(OFS_PARM0);
1454         val = G_STRING(OFS_PARM1);
1455
1456 // change the string in sv
1457         sv.lightstyles[style] = val;
1458
1459 // send message to all clients on this server
1460         if (sv.state != ss_active)
1461                 return;
1462
1463         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1464         {
1465                 if (client->netconnection)
1466                 {
1467                         MSG_WriteChar (&client->message, svc_lightstyle);
1468                         MSG_WriteChar (&client->message,style);
1469                         MSG_WriteString (&client->message, val);
1470                 }
1471         }
1472 }
1473
1474 void PF_rint (void)
1475 {
1476         float   f;
1477         f = G_FLOAT(OFS_PARM0);
1478         if (f > 0)
1479                 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1480         else
1481                 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1482 }
1483 void PF_floor (void)
1484 {
1485         G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1486 }
1487 void PF_ceil (void)
1488 {
1489         G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1490 }
1491
1492
1493 /*
1494 =============
1495 PF_checkbottom
1496 =============
1497 */
1498 void PF_checkbottom (void)
1499 {
1500         G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1501 }
1502
1503 /*
1504 =============
1505 PF_pointcontents
1506 =============
1507 */
1508 void PF_pointcontents (void)
1509 {
1510         G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1511 }
1512
1513 /*
1514 =============
1515 PF_nextent
1516
1517 entity nextent(entity)
1518 =============
1519 */
1520 void PF_nextent (void)
1521 {
1522         int             i;
1523         edict_t *ent;
1524
1525         i = G_EDICTNUM(OFS_PARM0);
1526         while (1)
1527         {
1528                 pr_xfunction->builtinsprofile++;
1529                 i++;
1530                 if (i == sv.num_edicts)
1531                 {
1532                         RETURN_EDICT(sv.edicts);
1533                         return;
1534                 }
1535                 ent = EDICT_NUM(i);
1536                 if (!ent->e->free)
1537                 {
1538                         RETURN_EDICT(ent);
1539                         return;
1540                 }
1541         }
1542 }
1543
1544 /*
1545 =============
1546 PF_aim
1547
1548 Pick a vector for the player to shoot along
1549 vector aim(entity, missilespeed)
1550 =============
1551 */
1552 void PF_aim (void)
1553 {
1554         edict_t *ent, *check, *bestent;
1555         vec3_t  start, dir, end, bestdir;
1556         int             i, j;
1557         trace_t tr;
1558         float   dist, bestdist;
1559         float   speed;
1560
1561         ent = G_EDICT(OFS_PARM0);
1562         if (ent == sv.edicts)
1563                 Host_Error("aim: can not use world entity\n");
1564         if (ent->e->free)
1565                 Host_Error("aim: can not use free entity\n");
1566         speed = G_FLOAT(OFS_PARM1);
1567
1568         VectorCopy (ent->v->origin, start);
1569         start[2] += 20;
1570
1571 // try sending a trace straight
1572         VectorCopy (pr_global_struct->v_forward, dir);
1573         VectorMA (start, 2048, dir, end);
1574         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1575         if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1576         && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1577         {
1578                 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1579                 return;
1580         }
1581
1582
1583 // try all possible entities
1584         VectorCopy (dir, bestdir);
1585         bestdist = sv_aim.value;
1586         bestent = NULL;
1587
1588         check = NEXT_EDICT(sv.edicts);
1589         for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1590         {
1591                 pr_xfunction->builtinsprofile++;
1592                 if (check->v->takedamage != DAMAGE_AIM)
1593                         continue;
1594                 if (check == ent)
1595                         continue;
1596                 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1597                         continue;       // don't aim at teammate
1598                 for (j=0 ; j<3 ; j++)
1599                         end[j] = check->v->origin[j]
1600                         + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1601                 VectorSubtract (end, start, dir);
1602                 VectorNormalize (dir);
1603                 dist = DotProduct (dir, pr_global_struct->v_forward);
1604                 if (dist < bestdist)
1605                         continue;       // to far to turn
1606                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1607                 if (tr.ent == check)
1608                 {       // can shoot at this one
1609                         bestdist = dist;
1610                         bestent = check;
1611                 }
1612         }
1613
1614         if (bestent)
1615         {
1616                 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1617                 dist = DotProduct (dir, pr_global_struct->v_forward);
1618                 VectorScale (pr_global_struct->v_forward, dist, end);
1619                 end[2] = dir[2];
1620                 VectorNormalize (end);
1621                 VectorCopy (end, G_VECTOR(OFS_RETURN));
1622         }
1623         else
1624         {
1625                 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1626         }
1627 }
1628
1629 /*
1630 ==============
1631 PF_changeyaw
1632
1633 This was a major timewaster in progs, so it was converted to C
1634 ==============
1635 */
1636 void PF_changeyaw (void)
1637 {
1638         edict_t         *ent;
1639         float           ideal, current, move, speed;
1640
1641         ent = PROG_TO_EDICT(pr_global_struct->self);
1642         if (ent == sv.edicts)
1643                 Host_Error("changeyaw: can not modify world entity\n");
1644         if (ent->e->free)
1645                 Host_Error("changeyaw: can not modify free entity\n");
1646         current = ANGLEMOD(ent->v->angles[1]);
1647         ideal = ent->v->ideal_yaw;
1648         speed = ent->v->yaw_speed;
1649
1650         if (current == ideal)
1651                 return;
1652         move = ideal - current;
1653         if (ideal > current)
1654         {
1655                 if (move >= 180)
1656                         move = move - 360;
1657         }
1658         else
1659         {
1660                 if (move <= -180)
1661                         move = move + 360;
1662         }
1663         if (move > 0)
1664         {
1665                 if (move > speed)
1666                         move = speed;
1667         }
1668         else
1669         {
1670                 if (move < -speed)
1671                         move = -speed;
1672         }
1673
1674         ent->v->angles[1] = ANGLEMOD (current + move);
1675 }
1676
1677 /*
1678 ==============
1679 PF_changepitch
1680 ==============
1681 */
1682 void PF_changepitch (void)
1683 {
1684         edict_t         *ent;
1685         float           ideal, current, move, speed;
1686         eval_t          *val;
1687
1688         ent = G_EDICT(OFS_PARM0);
1689         if (ent == sv.edicts)
1690                 Host_Error("changepitch: can not modify world entity\n");
1691         if (ent->e->free)
1692                 Host_Error("changepitch: can not modify free entity\n");
1693         current = ANGLEMOD( ent->v->angles[0] );
1694         if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1695                 ideal = val->_float;
1696         else
1697         {
1698                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1699                 return;
1700         }
1701         if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1702                 speed = val->_float;
1703         else
1704         {
1705                 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1706                 return;
1707         }
1708
1709         if (current == ideal)
1710                 return;
1711         move = ideal - current;
1712         if (ideal > current)
1713         {
1714                 if (move >= 180)
1715                         move = move - 360;
1716         }
1717         else
1718         {
1719                 if (move <= -180)
1720                         move = move + 360;
1721         }
1722         if (move > 0)
1723         {
1724                 if (move > speed)
1725                         move = speed;
1726         }
1727         else
1728         {
1729                 if (move < -speed)
1730                         move = -speed;
1731         }
1732
1733         ent->v->angles[0] = ANGLEMOD (current + move);
1734 }
1735
1736 /*
1737 ===============================================================================
1738
1739 MESSAGE WRITING
1740
1741 ===============================================================================
1742 */
1743
1744 #define MSG_BROADCAST   0               // unreliable to all
1745 #define MSG_ONE                 1               // reliable to one (msg_entity)
1746 #define MSG_ALL                 2               // reliable to all
1747 #define MSG_INIT                3               // write to the init string
1748
1749 sizebuf_t *WriteDest (void)
1750 {
1751         int             entnum;
1752         int             dest;
1753         edict_t *ent;
1754
1755         dest = G_FLOAT(OFS_PARM0);
1756         switch (dest)
1757         {
1758         case MSG_BROADCAST:
1759                 return &sv.datagram;
1760
1761         case MSG_ONE:
1762                 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1763                 entnum = NUM_FOR_EDICT(ent);
1764                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1765                         Host_Error("WriteDest: tried to write to non-client\n");
1766                 return &svs.clients[entnum-1].message;
1767
1768         case MSG_ALL:
1769                 return &sv.reliable_datagram;
1770
1771         case MSG_INIT:
1772                 return &sv.signon;
1773
1774         default:
1775                 Host_Error ("WriteDest: bad destination");
1776                 break;
1777         }
1778
1779         return NULL;
1780 }
1781
1782 void PF_WriteByte (void)
1783 {
1784         MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1785 }
1786
1787 void PF_WriteChar (void)
1788 {
1789         MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1790 }
1791
1792 void PF_WriteShort (void)
1793 {
1794         MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1795 }
1796
1797 void PF_WriteLong (void)
1798 {
1799         MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1800 }
1801
1802 void PF_WriteAngle (void)
1803 {
1804         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1805 }
1806
1807 void PF_WriteCoord (void)
1808 {
1809         MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1810 }
1811
1812 void PF_WriteString (void)
1813 {
1814         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1815 }
1816
1817
1818 void PF_WriteEntity (void)
1819 {
1820         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1821 }
1822
1823 //=============================================================================
1824
1825 void PF_makestatic (void)
1826 {
1827         edict_t *ent;
1828         int i, large;
1829
1830         ent = G_EDICT(OFS_PARM0);
1831         if (ent == sv.edicts)
1832                 Host_Error("makestatic: can not modify world entity\n");
1833         if (ent->e->free)
1834                 Host_Error("makestatic: can not modify free entity\n");
1835
1836         large = false;
1837         if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1838                 large = true;
1839
1840         if (large)
1841         {
1842                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1843                 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1844                 MSG_WriteShort (&sv.signon, ent->v->frame);
1845         }
1846         else
1847         {
1848                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1849                 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1850                 MSG_WriteByte (&sv.signon, ent->v->frame);
1851         }
1852
1853         MSG_WriteByte (&sv.signon, ent->v->colormap);
1854         MSG_WriteByte (&sv.signon, ent->v->skin);
1855         for (i=0 ; i<3 ; i++)
1856         {
1857                 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1858                 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1859         }
1860
1861 // throw the entity away now
1862         ED_Free (ent);
1863 }
1864
1865 //=============================================================================
1866
1867 /*
1868 ==============
1869 PF_setspawnparms
1870 ==============
1871 */
1872 void PF_setspawnparms (void)
1873 {
1874         edict_t *ent;
1875         int             i;
1876         client_t        *client;
1877
1878         ent = G_EDICT(OFS_PARM0);
1879         i = NUM_FOR_EDICT(ent);
1880         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1881         {
1882                 Con_Printf("tried to setspawnparms on a non-client\n");
1883                 return;
1884         }
1885
1886         // copy spawn parms out of the client_t
1887         client = svs.clients + i-1;
1888         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1889                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1890 }
1891
1892 /*
1893 ==============
1894 PF_changelevel
1895 ==============
1896 */
1897 void PF_changelevel (void)
1898 {
1899         char    *s;
1900
1901 // make sure we don't issue two changelevels
1902         if (svs.changelevel_issued)
1903                 return;
1904         svs.changelevel_issued = true;
1905
1906         s = G_STRING(OFS_PARM0);
1907         Cbuf_AddText (va("changelevel %s\n",s));
1908 }
1909
1910 void PF_sin (void)
1911 {
1912         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1913 }
1914
1915 void PF_cos (void)
1916 {
1917         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1918 }
1919
1920 void PF_sqrt (void)
1921 {
1922         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1923 }
1924
1925 /*
1926 =================
1927 PF_RandomVec
1928
1929 Returns a vector of length < 1
1930
1931 randomvec()
1932 =================
1933 */
1934 void PF_randomvec (void)
1935 {
1936         vec3_t          temp;
1937         do
1938         {
1939                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1940                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1941                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1942         }
1943         while (DotProduct(temp, temp) >= 1);
1944         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1945 }
1946
1947 /*
1948 =================
1949 PF_GetLight
1950
1951 Returns a color vector indicating the lighting at the requested point.
1952
1953 (Internal Operation note: actually measures the light beneath the point, just like
1954                           the model lighting on the client)
1955
1956 getlight(vector)
1957 =================
1958 */
1959 void PF_GetLight (void)
1960 {
1961         vec3_t ambientcolor, diffusecolor, diffusenormal;
1962         vec_t *p;
1963         p = G_VECTOR(OFS_PARM0);
1964         VectorClear(ambientcolor);
1965         VectorClear(diffusecolor);
1966         VectorClear(diffusenormal);
1967         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1968                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1969         VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1970 }
1971
1972 #define MAX_QC_CVARS 128
1973 cvar_t qc_cvar[MAX_QC_CVARS];
1974 int currentqc_cvar;
1975
1976 void PF_registercvar (void)
1977 {
1978         char *name, *value;
1979         cvar_t *variable;
1980         name = G_STRING(OFS_PARM0);
1981         value = G_STRING(OFS_PARM1);
1982         G_FLOAT(OFS_RETURN) = 0;
1983 // first check to see if it has already been defined
1984         if (Cvar_FindVar (name))
1985                 return;
1986
1987 // check for overlap with a command
1988         if (Cmd_Exists (name))
1989         {
1990                 Con_Printf ("PF_registercvar: %s is a command\n", name);
1991                 return;
1992         }
1993
1994         if (currentqc_cvar >= MAX_QC_CVARS)
1995                 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1996
1997 // copy the name and value
1998         variable = &qc_cvar[currentqc_cvar++];
1999         variable->name = Z_Malloc (strlen(name)+1);
2000         strcpy (variable->name, name);
2001         variable->string = Z_Malloc (strlen(value)+1);
2002         strcpy (variable->string, value);
2003         variable->value = atof (value);
2004
2005         Cvar_RegisterVariable(variable);
2006         G_FLOAT(OFS_RETURN) = 1; // success
2007 }
2008
2009 /*
2010 =================
2011 PF_min
2012
2013 returns the minimum of two supplied floats
2014
2015 min(a, b)
2016 =================
2017 */
2018 void PF_min (void)
2019 {
2020         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2021         if (pr_argc == 2)
2022                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2023         else if (pr_argc >= 3)
2024         {
2025                 int i;
2026                 float f = G_FLOAT(OFS_PARM0);
2027                 for (i = 1;i < pr_argc;i++)
2028                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
2029                                 f = G_FLOAT((OFS_PARM0+i*3));
2030                 G_FLOAT(OFS_RETURN) = f;
2031         }
2032         else
2033                 Host_Error("min: must supply at least 2 floats\n");
2034 }
2035
2036 /*
2037 =================
2038 PF_max
2039
2040 returns the maximum of two supplied floats
2041
2042 max(a, b)
2043 =================
2044 */
2045 void PF_max (void)
2046 {
2047         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2048         if (pr_argc == 2)
2049                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2050         else if (pr_argc >= 3)
2051         {
2052                 int i;
2053                 float f = G_FLOAT(OFS_PARM0);
2054                 for (i = 1;i < pr_argc;i++)
2055                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
2056                                 f = G_FLOAT((OFS_PARM0+i*3));
2057                 G_FLOAT(OFS_RETURN) = f;
2058         }
2059         else
2060                 Host_Error("max: must supply at least 2 floats\n");
2061 }
2062
2063 /*
2064 =================
2065 PF_bound
2066
2067 returns number bounded by supplied range
2068
2069 min(min, value, max)
2070 =================
2071 */
2072 void PF_bound (void)
2073 {
2074         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2075 }
2076
2077 /*
2078 =================
2079 PF_pow
2080
2081 returns a raised to power b
2082
2083 pow(a, b)
2084 =================
2085 */
2086 void PF_pow (void)
2087 {
2088         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2089 }
2090
2091 /*
2092 =================
2093 PF_copyentity
2094
2095 copies data from one entity to another
2096
2097 copyentity(src, dst)
2098 =================
2099 */
2100 void PF_copyentity (void)
2101 {
2102         edict_t *in, *out;
2103         in = G_EDICT(OFS_PARM0);
2104         if (in == sv.edicts)
2105                 Host_Error("copyentity: can not read world entity\n");
2106         if (in->e->free)
2107                 Host_Error("copyentity: can not read free entity\n");
2108         out = G_EDICT(OFS_PARM1);
2109         if (out == sv.edicts)
2110                 Host_Error("copyentity: can not modify world entity\n");
2111         if (out->e->free)
2112                 Host_Error("copyentity: can not modify free entity\n");
2113         memcpy(out->v, in->v, progs->entityfields * 4);
2114 }
2115
2116 /*
2117 =================
2118 PF_setcolor
2119
2120 sets the color of a client and broadcasts the update to all connected clients
2121
2122 setcolor(clientent, value)
2123 =================
2124 */
2125 void PF_setcolor (void)
2126 {
2127         client_t *client;
2128         int entnum, i;
2129         eval_t *val;
2130
2131         entnum = G_EDICTNUM(OFS_PARM0);
2132         i = G_FLOAT(OFS_PARM1);
2133
2134         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2135         {
2136                 Con_Printf ("tried to setcolor a non-client\n");
2137                 return;
2138         }
2139
2140         client = svs.clients + entnum-1;
2141         if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2142                 val->_float = i;
2143         client->colors = i;
2144         client->old_colors = i;
2145         client->edict->v->team = (i & 15) + 1;
2146
2147         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2148         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2149         MSG_WriteByte (&sv.reliable_datagram, i);
2150 }
2151
2152 /*
2153 =================
2154 PF_effect
2155
2156 effect(origin, modelname, startframe, framecount, framerate)
2157 =================
2158 */
2159 void PF_effect (void)
2160 {
2161         char *s;
2162         s = G_STRING(OFS_PARM1);
2163         if (!s || !s[0])
2164                 Host_Error("effect: no model specified\n");
2165
2166         SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2167 }
2168
2169 void PF_te_blood (void)
2170 {
2171         if (G_FLOAT(OFS_PARM2) < 1)
2172                 return;
2173         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2174         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2175         // origin
2176         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2177         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2178         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2179         // velocity
2180         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2181         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2182         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2183         // count
2184         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2185 }
2186
2187 void PF_te_bloodshower (void)
2188 {
2189         if (G_FLOAT(OFS_PARM3) < 1)
2190                 return;
2191         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2192         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2193         // min
2194         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2195         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2196         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2197         // max
2198         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2199         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2200         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2201         // speed
2202         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2203         // count
2204         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2205 }
2206
2207 void PF_te_explosionrgb (void)
2208 {
2209         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2210         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2211         // origin
2212         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2213         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2214         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2215         // color
2216         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2217         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2218         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2219 }
2220
2221 void PF_te_particlecube (void)
2222 {
2223         if (G_FLOAT(OFS_PARM3) < 1)
2224                 return;
2225         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2226         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2227         // min
2228         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2229         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2230         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2231         // max
2232         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2233         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2234         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2235         // velocity
2236         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2237         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2238         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2239         // count
2240         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2241         // color
2242         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2243         // gravity true/false
2244         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2245         // randomvel
2246         MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2247 }
2248
2249 void PF_te_particlerain (void)
2250 {
2251         if (G_FLOAT(OFS_PARM3) < 1)
2252                 return;
2253         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2254         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2255         // min
2256         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2257         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2258         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2259         // max
2260         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2261         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2262         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2263         // velocity
2264         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2265         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2266         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2267         // count
2268         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2269         // color
2270         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2271 }
2272
2273 void PF_te_particlesnow (void)
2274 {
2275         if (G_FLOAT(OFS_PARM3) < 1)
2276                 return;
2277         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2279         // min
2280         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2281         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2282         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2283         // max
2284         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2285         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2286         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2287         // velocity
2288         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2289         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2290         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2291         // count
2292         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2293         // color
2294         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2295 }
2296
2297 void PF_te_spark (void)
2298 {
2299         if (G_FLOAT(OFS_PARM2) < 1)
2300                 return;
2301         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2302         MSG_WriteByte(&sv.datagram, TE_SPARK);
2303         // origin
2304         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2305         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2306         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2307         // velocity
2308         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2309         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2310         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2311         // count
2312         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2313 }
2314
2315 void PF_te_gunshotquad (void)
2316 {
2317         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2318         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2319         // origin
2320         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2321         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2322         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2323 }
2324
2325 void PF_te_spikequad (void)
2326 {
2327         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2328         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2329         // origin
2330         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2331         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2332         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2333 }
2334
2335 void PF_te_superspikequad (void)
2336 {
2337         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2338         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2339         // origin
2340         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2341         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2342         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2343 }
2344
2345 void PF_te_explosionquad (void)
2346 {
2347         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2349         // origin
2350         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2351         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2352         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2353 }
2354
2355 void PF_te_smallflash (void)
2356 {
2357         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2358         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2359         // origin
2360         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2361         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2362         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2363 }
2364
2365 void PF_te_customflash (void)
2366 {
2367         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2368                 return;
2369         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2370         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2371         // origin
2372         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2373         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2374         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2375         // radius
2376         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2377         // lifetime
2378         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2379         // color
2380         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2381         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2382         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2383 }
2384
2385 void PF_te_gunshot (void)
2386 {
2387         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2388         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2389         // origin
2390         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2391         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2392         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2393 }
2394
2395 void PF_te_spike (void)
2396 {
2397         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2398         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2399         // origin
2400         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2401         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2402         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2403 }
2404
2405 void PF_te_superspike (void)
2406 {
2407         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2408         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2409         // origin
2410         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2411         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2412         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2413 }
2414
2415 void PF_te_explosion (void)
2416 {
2417         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2419         // origin
2420         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2421         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2422         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2423 }
2424
2425 void PF_te_tarexplosion (void)
2426 {
2427         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2428         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2429         // origin
2430         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2431         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2432         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2433 }
2434
2435 void PF_te_wizspike (void)
2436 {
2437         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2438         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2439         // origin
2440         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2441         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2442         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2443 }
2444
2445 void PF_te_knightspike (void)
2446 {
2447         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2448         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2449         // origin
2450         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2451         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2452         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2453 }
2454
2455 void PF_te_lavasplash (void)
2456 {
2457         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2458         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2459         // origin
2460         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2461         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2462         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2463 }
2464
2465 void PF_te_teleport (void)
2466 {
2467         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2468         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2469         // origin
2470         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2471         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2472         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2473 }
2474
2475 void PF_te_explosion2 (void)
2476 {
2477         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2478         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2479         // origin
2480         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2481         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2482         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2483         // color
2484         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2485 }
2486
2487 void PF_te_lightning1 (void)
2488 {
2489         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2490         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2491         // owner entity
2492         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2493         // start
2494         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2495         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2496         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2497         // end
2498         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2499         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2500         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2501 }
2502
2503 void PF_te_lightning2 (void)
2504 {
2505         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2506         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2507         // owner entity
2508         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2509         // start
2510         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2511         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2512         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2513         // end
2514         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2515         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2516         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2517 }
2518
2519 void PF_te_lightning3 (void)
2520 {
2521         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2522         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2523         // owner entity
2524         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2525         // start
2526         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2527         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2528         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2529         // end
2530         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2531         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2532         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2533 }
2534
2535 void PF_te_beam (void)
2536 {
2537         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2538         MSG_WriteByte(&sv.datagram, TE_BEAM);
2539         // owner entity
2540         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2541         // start
2542         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2543         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2544         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2545         // end
2546         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2547         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2548         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2549 }
2550
2551 void PF_te_plasmaburn (void)
2552 {
2553         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2554         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2555         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2556         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2557         MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2558 }
2559
2560 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2561 {
2562         int i, j;
2563         vec3_t v1, clipplanenormal, normal;
2564         vec_t clipplanedist, clipdist;
2565         VectorCopy(p, out);
2566         if (surf->flags & SURF_PLANEBACK)
2567                 VectorNegate(surf->plane->normal, normal);
2568         else
2569                 VectorCopy(surf->plane->normal, normal);
2570         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2571         {
2572                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2573                 VectorNormalizeFast(v1);
2574                 CrossProduct(v1, normal, clipplanenormal);
2575                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2576                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2577                 if (clipdist > 0)
2578                 {
2579                         clipdist = -clipdist;
2580                         VectorMA(out, clipdist, clipplanenormal, out);
2581                 }
2582         }
2583 }
2584
2585 static msurface_t *getsurface(edict_t *ed, int surfnum)
2586 {
2587         int modelindex;
2588         model_t *model;
2589         if (!ed || ed->e->free)
2590                 return NULL;
2591         modelindex = ed->v->modelindex;
2592         if (modelindex < 1 || modelindex >= MAX_MODELS)
2593                 return NULL;
2594         model = sv.models[modelindex];
2595         if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2596                 return NULL;
2597         return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2598 }
2599
2600
2601 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2602 void PF_getsurfacenumpoints(void)
2603 {
2604         msurface_t *surf;
2605         // return 0 if no such surface
2606         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2607         {
2608                 G_FLOAT(OFS_RETURN) = 0;
2609                 return;
2610         }
2611
2612         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2613 }
2614 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2615 void PF_getsurfacepoint(void)
2616 {
2617         edict_t *ed;
2618         msurface_t *surf;
2619         int pointnum;
2620         VectorClear(G_VECTOR(OFS_RETURN));
2621         ed = G_EDICT(OFS_PARM0);
2622         if (!ed || ed->e->free)
2623                 return;
2624         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2625                 return;
2626         pointnum = G_FLOAT(OFS_PARM2);
2627         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2628                 return;
2629         // FIXME: implement rotation/scaling
2630         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2631 }
2632 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2633 void PF_getsurfacenormal(void)
2634 {
2635         msurface_t *surf;
2636         VectorClear(G_VECTOR(OFS_RETURN));
2637         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2638                 return;
2639         // FIXME: implement rotation/scaling
2640         if (surf->flags & SURF_PLANEBACK)
2641                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2642         else
2643                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2644 }
2645 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2646 void PF_getsurfacetexture(void)
2647 {
2648         msurface_t *surf;
2649         G_INT(OFS_RETURN) = 0;
2650         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2651                 return;
2652         G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2653 }
2654 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2655 void PF_getsurfacenearpoint(void)
2656 {
2657         int surfnum, best, modelindex;
2658         vec3_t clipped, p;
2659         vec_t dist, bestdist;
2660         edict_t *ed;
2661         model_t *model;
2662         msurface_t *surf;
2663         vec_t *point;
2664         G_FLOAT(OFS_RETURN) = -1;
2665         ed = G_EDICT(OFS_PARM0);
2666         point = G_VECTOR(OFS_PARM1);
2667
2668         if (!ed || ed->e->free)
2669                 return;
2670         modelindex = ed->v->modelindex;
2671         if (modelindex < 1 || modelindex >= MAX_MODELS)
2672                 return;
2673         model = sv.models[modelindex];
2674         if (!model->brushq1.numsurfaces)
2675                 return;
2676
2677         // FIXME: implement rotation/scaling
2678         VectorSubtract(point, ed->v->origin, p);
2679         best = -1;
2680         bestdist = 1000000000;
2681         for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2682         {
2683                 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2684                 dist = PlaneDiff(p, surf->plane);
2685                 dist = dist * dist;
2686                 if (dist < bestdist)
2687                 {
2688                         clippointtosurface(surf, p, clipped);
2689                         VectorSubtract(clipped, p, clipped);
2690                         dist += DotProduct(clipped, clipped);
2691                         if (dist < bestdist)
2692                         {
2693                                 best = surfnum;
2694                                 bestdist = dist;
2695                         }
2696                 }
2697         }
2698         G_FLOAT(OFS_RETURN) = best;
2699 }
2700 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2701 void PF_getsurfaceclippedpoint(void)
2702 {
2703         edict_t *ed;
2704         msurface_t *surf;
2705         vec3_t p, out;
2706         VectorClear(G_VECTOR(OFS_RETURN));
2707         ed = G_EDICT(OFS_PARM0);
2708         if (!ed || ed->e->free)
2709                 return;
2710         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2711                 return;
2712         // FIXME: implement rotation/scaling
2713         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2714         clippointtosurface(surf, p, out);
2715         // FIXME: implement rotation/scaling
2716         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2717 }
2718
2719 #define MAX_PRFILES 256
2720
2721 qfile_t *pr_files[MAX_PRFILES];
2722
2723 void PR_Files_Init(void)
2724 {
2725         memset(pr_files, 0, sizeof(pr_files));
2726 }
2727
2728 void PR_Files_CloseAll(void)
2729 {
2730         int i;
2731         for (i = 0;i < MAX_PRFILES;i++)
2732         {
2733                 if (pr_files[i])
2734                         FS_Close(pr_files[i]);
2735                 pr_files[i] = NULL;
2736         }
2737 }
2738
2739 //float(string s) stof = #81; // get numerical value from a string
2740 void PF_stof(void)
2741 {
2742         char string[STRINGTEMP_LENGTH];
2743         PF_VarString(0, string, sizeof(string));
2744         G_FLOAT(OFS_RETURN) = atof(string);
2745 }
2746
2747 //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
2748 void PF_fopen(void)
2749 {
2750         int filenum, mode;
2751         char *modestring, *filename;
2752         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2753                 if (pr_files[filenum] == NULL)
2754                         break;
2755         if (filenum >= MAX_PRFILES)
2756         {
2757                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2758                 G_FLOAT(OFS_RETURN) = -2;
2759                 return;
2760         }
2761         mode = G_FLOAT(OFS_PARM1);
2762         switch(mode)
2763         {
2764         case 0: // FILE_READ
2765                 modestring = "rb";
2766                 break;
2767         case 1: // FILE_APPEND
2768                 modestring = "ab";
2769                 break;
2770         case 2: // FILE_WRITE
2771                 modestring = "wb";
2772                 break;
2773         default:
2774                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2775                 G_FLOAT(OFS_RETURN) = -3;
2776                 return;
2777         }
2778         filename = G_STRING(OFS_PARM0);
2779         // .. is parent directory on many platforms
2780         // / is parent directory on Amiga
2781         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2782         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2783         if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2784         {
2785                 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2786                 G_FLOAT(OFS_RETURN) = -4;
2787                 return;
2788         }
2789         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2790         if (pr_files[filenum] == NULL)
2791                 G_FLOAT(OFS_RETURN) = -1;
2792         else
2793                 G_FLOAT(OFS_RETURN) = filenum;
2794 }
2795
2796 //void(float fhandle) fclose = #111; // closes a file
2797 void PF_fclose(void)
2798 {
2799         int filenum = G_FLOAT(OFS_PARM0);
2800         if (filenum < 0 || filenum >= MAX_PRFILES)
2801         {
2802                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2803                 return;
2804         }
2805         if (pr_files[filenum] == NULL)
2806         {
2807                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2808                 return;
2809         }
2810         FS_Close(pr_files[filenum]);
2811         pr_files[filenum] = NULL;
2812 }
2813
2814 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2815 void PF_fgets(void)
2816 {
2817         int c, end;
2818         static char string[STRINGTEMP_LENGTH];
2819         int filenum = G_FLOAT(OFS_PARM0);
2820         if (filenum < 0 || filenum >= MAX_PRFILES)
2821         {
2822                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2823                 return;
2824         }
2825         if (pr_files[filenum] == NULL)
2826         {
2827                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2828                 return;
2829         }
2830         end = 0;
2831         for (;;)
2832         {
2833                 c = FS_Getc(pr_files[filenum]);
2834                 if (c == '\r' || c == '\n' || c < 0)
2835                         break;
2836                 if (end < STRINGTEMP_LENGTH - 1)
2837                         string[end++] = c;
2838         }
2839         string[end] = 0;
2840         // remove \n following \r
2841         if (c == '\r')
2842                 c = FS_Getc(pr_files[filenum]);
2843         if (developer.integer)
2844                 Con_Printf("fgets: %s\n", string);
2845         if (c >= 0)
2846                 G_INT(OFS_RETURN) = PR_SetString(string);
2847         else
2848                 G_INT(OFS_RETURN) = 0;
2849 }
2850
2851 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2852 void PF_fputs(void)
2853 {
2854         int stringlength;
2855         char string[STRINGTEMP_LENGTH];
2856         int filenum = G_FLOAT(OFS_PARM0);
2857         if (filenum < 0 || filenum >= MAX_PRFILES)
2858         {
2859                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2860                 return;
2861         }
2862         if (pr_files[filenum] == NULL)
2863         {
2864                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2865                 return;
2866         }
2867         PF_VarString(1, string, sizeof(string));
2868         if ((stringlength = strlen(string)))
2869                 FS_Write(pr_files[filenum], string, stringlength);
2870         if (developer.integer)
2871                 Con_Printf("fputs: %s\n", string);
2872 }
2873
2874 //float(string s) strlen = #114; // returns how many characters are in a string
2875 void PF_strlen(void)
2876 {
2877         char *s;
2878         s = G_STRING(OFS_PARM0);
2879         if (s)
2880                 G_FLOAT(OFS_RETURN) = strlen(s);
2881         else
2882                 G_FLOAT(OFS_RETURN) = 0;
2883 }
2884
2885 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2886 void PF_strcat(void)
2887 {
2888         char *s = PR_GetTempString();
2889         PF_VarString(0, s, STRINGTEMP_LENGTH);
2890         G_INT(OFS_RETURN) = PR_SetString(s);
2891 }
2892
2893 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2894 void PF_substring(void)
2895 {
2896         int i, start, length;
2897         char *s, *string = PR_GetTempString();
2898         s = G_STRING(OFS_PARM0);
2899         start = G_FLOAT(OFS_PARM1);
2900         length = G_FLOAT(OFS_PARM2);
2901         if (!s)
2902                 s = "";
2903         for (i = 0;i < start && *s;i++, s++);
2904         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2905                 string[i] = *s;
2906         string[i] = 0;
2907         G_INT(OFS_RETURN) = PR_SetString(string);
2908 }
2909
2910 //vector(string s) stov = #117; // returns vector value from a string
2911 void PF_stov(void)
2912 {
2913         char string[STRINGTEMP_LENGTH];
2914         PF_VarString(0, string, sizeof(string));
2915         Math_atov(string, G_VECTOR(OFS_RETURN));
2916 }
2917
2918 //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)
2919 void PF_strzone(void)
2920 {
2921         char *in, *out;
2922         in = G_STRING(OFS_PARM0);
2923         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2924         strcpy(out, in);
2925         G_INT(OFS_RETURN) = PR_SetString(out);
2926 }
2927
2928 //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!!!)
2929 void PF_strunzone(void)
2930 {
2931         Mem_Free(G_STRING(OFS_PARM0));
2932 }
2933
2934 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2935 //this function originally written by KrimZon, made shorter by LordHavoc
2936 void PF_clientcommand (void)
2937 {
2938         client_t *temp_client;
2939         int i;
2940
2941         //find client for this entity
2942         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2943         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2944         {
2945                 Con_Printf("PF_clientcommand: entity is not a client");
2946                 return;
2947         }
2948
2949         temp_client = host_client;
2950         host_client = svs.clients + i;
2951         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2952         host_client = temp_client;
2953 }
2954
2955 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2956 //this function originally written by KrimZon, made shorter by LordHavoc
2957 char **tokens = NULL;
2958 int    max_tokens, num_tokens = 0;
2959 void PF_tokenize (void)
2960 {
2961         const char *p;
2962         char *str;
2963         str = G_STRING(OFS_PARM0);
2964
2965         if (tokens != NULL)
2966         {
2967                 int i;
2968                 for (i=0;i<num_tokens;i++)
2969                         Z_Free(tokens[i]);
2970                 Z_Free(tokens);
2971                 num_tokens = 0;
2972         }
2973
2974         tokens = Z_Malloc(strlen(str) * sizeof(char *));
2975         max_tokens = strlen(str);
2976
2977         for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2978         {
2979                 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2980                 strcpy(tokens[num_tokens], com_token);
2981         }
2982
2983         G_FLOAT(OFS_RETURN) = num_tokens;
2984 }
2985
2986 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2987 //this function originally written by KrimZon, made shorter by LordHavoc
2988 void PF_argv (void)
2989 {
2990         int token_num = G_FLOAT(OFS_PARM0);
2991         if (token_num >= 0 && token_num < num_tokens)
2992                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2993         else
2994                 G_INT(OFS_RETURN) = PR_SetString("");
2995 }
2996
2997 //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)
2998 void PF_setattachment (void)
2999 {
3000         edict_t *e = G_EDICT(OFS_PARM0);
3001         edict_t *tagentity = G_EDICT(OFS_PARM1);
3002         char *tagname = G_STRING(OFS_PARM2);
3003         eval_t *v;
3004         int i, modelindex;
3005         model_t *model;
3006
3007         if (e == sv.edicts)
3008                 Host_Error("setattachment: can not modify world entity\n");
3009         if (e->e->free)
3010                 Host_Error("setattachment: can not modify free entity\n");
3011
3012         if (tagentity == NULL)
3013                 tagentity = sv.edicts;
3014
3015         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3016         if (v)
3017                 v->edict = EDICT_TO_PROG(tagentity);
3018
3019         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3020         if (v)
3021                 v->_float = 0;
3022         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3023         {
3024                 modelindex = (int)tagentity->v->modelindex;
3025                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3026                 {
3027                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3028                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3029                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3030                                                 v->_float = i + 1;
3031                         if (v->_float == 0 && model->alias.aliasnum_tags)
3032                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3033                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3034                                                 v->_float = i + 1;
3035                         if (v->_float == 0)
3036                                 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);
3037                 }
3038                 else
3039                         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));
3040         }
3041 }
3042
3043
3044 builtin_t pr_builtin[] =
3045 {
3046 NULL,                                           // #0
3047 PF_makevectors,                         // #1 void(entity e) makevectors
3048 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3049 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3050 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3051 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3052 PF_break,                                       // #6 void() break
3053 PF_random,                                      // #7 float() random
3054 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3055 PF_normalize,                           // #9 vector(vector v) normalize
3056 PF_error,                                       // #10 void(string e) error
3057 PF_objerror,                            // #11 void(string e) objerror
3058 PF_vlen,                                        // #12 float(vector v) vlen
3059 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3060 PF_Spawn,                                       // #14 entity() spawn
3061 PF_Remove,                                      // #15 void(entity e) remove
3062 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3063 PF_checkclient,                         // #17 entity() clientlist
3064 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3065 PF_precache_sound,                      // #19 void(string s) precache_sound
3066 PF_precache_model,                      // #20 void(string s) precache_model
3067 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3068 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3069 PF_bprint,                                      // #23 void(string s) bprint
3070 PF_sprint,                                      // #24 void(entity client, string s) sprint
3071 PF_dprint,                                      // #25 void(string s) dprint
3072 PF_ftos,                                        // #26 void(string s) ftos
3073 PF_vtos,                                        // #27 void(string s) vtos
3074 PF_coredump,                            // #28 void() coredump
3075 PF_traceon,                                     // #29 void() traceon
3076 PF_traceoff,                            // #30 void() traceoff
3077 PF_eprint,                                      // #31 void(entity e) eprint
3078 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3079 NULL,                                           // #33
3080 PF_droptofloor,                         // #34 float() droptofloor
3081 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3082 PF_rint,                                        // #36 float(float v) rint
3083 PF_floor,                                       // #37 float(float v) floor
3084 PF_ceil,                                        // #38 float(float v) ceil
3085 NULL,                                           // #39
3086 PF_checkbottom,                         // #40 float(entity e) checkbottom
3087 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3088 NULL,                                           // #42
3089 PF_fabs,                                        // #43 float(float f) fabs
3090 PF_aim,                                         // #44 vector(entity e, float speed) aim
3091 PF_cvar,                                        // #45 float(string s) cvar
3092 PF_localcmd,                            // #46 void(string s) localcmd
3093 PF_nextent,                                     // #47 entity(entity e) nextent
3094 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3095 PF_changeyaw,                           // #49 void() ChangeYaw
3096 NULL,                                           // #50
3097 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3098 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3099 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3100 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3101 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3102 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3103 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3104 PF_WriteString,                         // #58 void(float to, string s) WriteString
3105 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3106 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3107 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3108 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3109 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3110 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3111 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3112 NULL,                                           // #66
3113 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3114 PF_precache_file,                       // #68 string(string s) precache_file
3115 PF_makestatic,                          // #69 void(entity e) makestatic
3116 PF_changelevel,                         // #70 void(string s) changelevel
3117 NULL,                                           // #71
3118 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3119 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3120 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3121 PF_precache_model,                      // #75 string(string s) precache_model2
3122 PF_precache_sound,                      // #76 string(string s) precache_sound2
3123 PF_precache_file,                       // #77 string(string s) precache_file2
3124 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3125 NULL,                                           // #79
3126 NULL,                                           // #80
3127 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3128 NULL,                                           // #82
3129 NULL,                                           // #83
3130 NULL,                                           // #84
3131 NULL,                                           // #85
3132 NULL,                                           // #86
3133 NULL,                                           // #87
3134 NULL,                                           // #88
3135 NULL,                                           // #89
3136 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3137 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3138 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3139 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3140 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3141 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3142 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3143 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3144 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3145 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3146 NULL,                                           // #100
3147 NULL,                                           // #101
3148 NULL,                                           // #102
3149 NULL,                                           // #103
3150 NULL,                                           // #104
3151 NULL,                                           // #105
3152 NULL,                                           // #106
3153 NULL,                                           // #107
3154 NULL,                                           // #108
3155 NULL,                                           // #109
3156 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3157 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3158 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3159 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3160 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3161 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3162 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3163 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3164 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3165 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3166 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3167 a a a a a a a a                         // #120-199
3168 a a a a a a a a a a                     // #200-299
3169 a a a a a a a a a a                     // #300-399
3170 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3171 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3172 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3173 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3174 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3175 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3176 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3177 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3178 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3179 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3180 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3181 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3182 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3183 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3184 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3185 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3186 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3187 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3188 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3189 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3190 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3191 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3192 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3193 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3194 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3195 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3196 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3197 PF_te_explosion2,                       // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3198 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3199 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3200 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3201 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3202 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3203 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3204 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3205 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3206 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3207 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3208 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3209 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3210 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3211 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3212 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3213 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3214 NULL,                                           // #444
3215 NULL,                                           // #445
3216 NULL,                                           // #446
3217 NULL,                                           // #447
3218 NULL,                                           // #448
3219 NULL,                                           // #449
3220 a a a a a                                       // #450-499 (LordHavoc)
3221 };
3222
3223 builtin_t *pr_builtins = pr_builtin;
3224 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3225
3226 void PR_Cmd_Init(void)
3227 {
3228         pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3229         PR_Files_Init();
3230 }
3231
3232 void PR_Cmd_Reset(void)
3233 {
3234         Mem_EmptyPool(pr_strings_mempool);
3235         PR_Files_CloseAll();
3236 }
3237