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