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