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