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