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