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