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