]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
fix problems with losing colors on connect and leaving ghosts on the scoreboard and...
[divverent/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
25
26 mempool_t *pr_strings_mempool;
27
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
33
34 static char *PR_GetTempString(void)
35 {
36         char *s;
37         s = pr_string_temp[pr_string_tempindex];
38         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
39         return s;
40 }
41
42 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
43 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
44 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
45
46
47 /*
48 ===============================================================================
49
50                                                 BUILT-IN FUNCTIONS
51
52 ===============================================================================
53 */
54
55
56 void PF_VarString(int first, char *out, int outlength)
57 {
58         int i;
59         const char *s;
60         char *outend;
61
62         outend = out + outlength - 1;
63         for (i = first;i < pr_argc && out < outend;i++)
64         {
65                 s = G_STRING((OFS_PARM0+i*3));
66                 while (out < outend && *s)
67                         *out++ = *s++;
68         }
69         *out++ = 0;
70 }
71
72 char *ENGINE_EXTENSIONS =
73 "DP_CL_LOADSKY "
74 "DP_EF_ADDITIVE "
75 "DP_EF_BLUE "
76 "DP_EF_FLAME "
77 "DP_EF_FULLBRIGHT "
78 "DP_EF_NODEPTHTEST "
79 "DP_EF_NODRAW "
80 "DP_EF_NOSHADOW "
81 "DP_EF_RED "
82 "DP_EF_STARDUST "
83 "DP_ENT_ALPHA "
84 "DP_ENT_CUSTOMCOLORMAP "
85 "DP_ENT_EXTERIORMODELTOCLIENT "
86 "DP_ENT_GLOW "
87 "DP_ENT_LOWPRECISION "
88 "DP_ENT_SCALE "
89 "DP_ENT_VIEWMODEL "
90 "DP_GFX_EXTERNALTEXTURES "
91 "DP_GFX_FOG "
92 "DP_GFX_QUAKE3MODELTAGS "
93 "DP_GFX_SKINFILES "
94 "DP_GFX_SKYBOX "
95 "DP_HALFLIFE_MAP "
96 "DP_HALFLIFE_MAP_CVAR "
97 "DP_INPUTBUTTONS "
98 "DP_LITSPRITES "
99 "DP_LITSUPPORT "
100 "DP_MONSTERWALK "
101 "DP_MOVETYPEBOUNCEMISSILE "
102 "DP_MOVETYPEFOLLOW "
103 "DP_QC_CHANGEPITCH "
104 "DP_QC_COPYENTITY "
105 "DP_QC_CVAR_STRING "
106 "DP_QC_ETOS "
107 "DP_QC_FINDCHAIN "
108 "DP_QC_FINDCHAINFLAGS "
109 "DP_QC_FINDCHAINFLOAT "
110 "DP_QC_FINDFLAGS "
111 "DP_QC_FINDFLOAT "
112 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
113 "DP_QC_GETLIGHT "
114 "DP_QC_GETSURFACE "
115 "DP_QC_GETTAGINFO "
116 "DP_QC_MINMAXBOUND "
117 "DP_QC_MULTIPLETEMPSTRINGS "
118 "DP_QC_RANDOMVEC "
119 "DP_QC_SINCOSSQRTPOW "
120 "DP_QC_TRACEBOX "
121 "DP_QC_TRACETOSS "
122 "DP_QC_TRACE_MOVETYPE_HITMODEL "
123 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
124 "DP_QC_VECTORVECTORS "
125 "DP_QUAKE2_MODEL "
126 "DP_QUAKE3_MODEL "
127 "DP_REGISTERCVAR "
128 "DP_SND_DIRECTIONLESSATTNNONE "
129 "DP_SND_OGGVORBIS "
130 "DP_SND_STEREOWAV "
131 "DP_SOLIDCORPSE "
132 "DP_SPRITE32 "
133 "DP_SV_DRAWONLYTOCLIENT "
134 "DP_SV_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 (client->edict)
2222         {
2223                 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2224                         val->_float = i;
2225                 client->edict->v->team = (i & 15) + 1;
2226         }
2227         client->colors = i;
2228         if (client->old_colors != client->colors)
2229         {
2230                 client->old_colors = client->colors;
2231                 // send notification to all clients
2232                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2233                 MSG_WriteByte (&sv.reliable_datagram, client->number);
2234                 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2235         }
2236 }
2237
2238 /*
2239 =================
2240 PF_effect
2241
2242 effect(origin, modelname, startframe, framecount, framerate)
2243 =================
2244 */
2245 void PF_effect (void)
2246 {
2247         int i;
2248         char *s;
2249         s = G_STRING(OFS_PARM1);
2250         if (!s || !s[0])
2251                 PF_WARNING("effect: no model specified\n");
2252
2253         i = SV_ModelIndex(s);
2254         if (i < 0)
2255                 PF_WARNING("effect: model not precached\n");
2256         SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2257 }
2258
2259 void PF_te_blood (void)
2260 {
2261         if (G_FLOAT(OFS_PARM2) < 1)
2262                 return;
2263         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2264         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2265         // origin
2266         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2267         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2268         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2269         // velocity
2270         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2271         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2272         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2273         // count
2274         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2275 }
2276
2277 void PF_te_bloodshower (void)
2278 {
2279         if (G_FLOAT(OFS_PARM3) < 1)
2280                 return;
2281         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2282         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2283         // min
2284         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2285         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2286         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2287         // max
2288         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2289         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2290         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2291         // speed
2292         MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2293         // count
2294         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2295 }
2296
2297 void PF_te_explosionrgb (void)
2298 {
2299         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2300         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2301         // origin
2302         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2303         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2304         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2305         // color
2306         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2307         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2308         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2309 }
2310
2311 void PF_te_particlecube (void)
2312 {
2313         if (G_FLOAT(OFS_PARM3) < 1)
2314                 return;
2315         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2316         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2317         // min
2318         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2319         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2320         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2321         // max
2322         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2323         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2324         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2325         // velocity
2326         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2327         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2328         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2329         // count
2330         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2331         // color
2332         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2333         // gravity true/false
2334         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2335         // randomvel
2336         MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2337 }
2338
2339 void PF_te_particlerain (void)
2340 {
2341         if (G_FLOAT(OFS_PARM3) < 1)
2342                 return;
2343         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2344         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2345         // min
2346         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2347         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2348         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2349         // max
2350         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2351         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2352         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2353         // velocity
2354         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2355         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2356         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2357         // count
2358         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2359         // color
2360         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2361 }
2362
2363 void PF_te_particlesnow (void)
2364 {
2365         if (G_FLOAT(OFS_PARM3) < 1)
2366                 return;
2367         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2368         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2369         // min
2370         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2371         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2372         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2373         // max
2374         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2375         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2376         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2377         // velocity
2378         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2379         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2380         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2381         // count
2382         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2383         // color
2384         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2385 }
2386
2387 void PF_te_spark (void)
2388 {
2389         if (G_FLOAT(OFS_PARM2) < 1)
2390                 return;
2391         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392         MSG_WriteByte(&sv.datagram, TE_SPARK);
2393         // origin
2394         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2395         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2396         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2397         // velocity
2398         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2399         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2400         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2401         // count
2402         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2403 }
2404
2405 void PF_te_gunshotquad (void)
2406 {
2407         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2408         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2409         // origin
2410         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2411         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2412         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2413 }
2414
2415 void PF_te_spikequad (void)
2416 {
2417         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2419         // origin
2420         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2421         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2422         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2423 }
2424
2425 void PF_te_superspikequad (void)
2426 {
2427         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2428         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2429         // origin
2430         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2431         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2432         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2433 }
2434
2435 void PF_te_explosionquad (void)
2436 {
2437         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2438         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2439         // origin
2440         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2441         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2442         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2443 }
2444
2445 void PF_te_smallflash (void)
2446 {
2447         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2448         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2449         // origin
2450         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2451         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2452         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2453 }
2454
2455 void PF_te_customflash (void)
2456 {
2457         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2458                 return;
2459         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2461         // origin
2462         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2463         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2464         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2465         // radius
2466         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2467         // lifetime
2468         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2469         // color
2470         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2471         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2472         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2473 }
2474
2475 void PF_te_gunshot (void)
2476 {
2477         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2478         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2479         // origin
2480         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2481         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2482         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2483 }
2484
2485 void PF_te_spike (void)
2486 {
2487         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2488         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2489         // origin
2490         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2491         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2492         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2493 }
2494
2495 void PF_te_superspike (void)
2496 {
2497         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2498         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2499         // origin
2500         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2501         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2502         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2503 }
2504
2505 void PF_te_explosion (void)
2506 {
2507         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2508         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2509         // origin
2510         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2511         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2512         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2513 }
2514
2515 void PF_te_tarexplosion (void)
2516 {
2517         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2518         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2519         // origin
2520         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2521         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2522         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2523 }
2524
2525 void PF_te_wizspike (void)
2526 {
2527         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2528         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2529         // origin
2530         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2531         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2532         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2533 }
2534
2535 void PF_te_knightspike (void)
2536 {
2537         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2538         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2539         // origin
2540         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2541         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2542         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2543 }
2544
2545 void PF_te_lavasplash (void)
2546 {
2547         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2548         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2549         // origin
2550         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2551         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2552         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2553 }
2554
2555 void PF_te_teleport (void)
2556 {
2557         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2558         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2559         // origin
2560         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2561         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2562         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2563 }
2564
2565 void PF_te_explosion2 (void)
2566 {
2567         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2568         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2569         // origin
2570         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2571         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2572         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2573         // color
2574         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2575         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2576 }
2577
2578 void PF_te_lightning1 (void)
2579 {
2580         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2581         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2582         // owner entity
2583         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2584         // start
2585         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2586         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2587         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2588         // end
2589         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2590         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2591         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2592 }
2593
2594 void PF_te_lightning2 (void)
2595 {
2596         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2597         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2598         // owner entity
2599         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2600         // start
2601         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2602         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2603         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2604         // end
2605         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2606         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2607         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2608 }
2609
2610 void PF_te_lightning3 (void)
2611 {
2612         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2613         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2614         // owner entity
2615         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2616         // start
2617         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2618         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2619         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2620         // end
2621         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2622         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2623         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2624 }
2625
2626 void PF_te_beam (void)
2627 {
2628         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2629         MSG_WriteByte(&sv.datagram, TE_BEAM);
2630         // owner entity
2631         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2632         // start
2633         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2634         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2635         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2636         // end
2637         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2638         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2639         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2640 }
2641
2642 void PF_te_plasmaburn (void)
2643 {
2644         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2645         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2646         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2647         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2648         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2649 }
2650
2651 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2652 {
2653         int i, j;
2654         vec3_t v1, clipplanenormal, normal;
2655         vec_t clipplanedist, clipdist;
2656         VectorCopy(p, out);
2657         if (surf->flags & SURF_PLANEBACK)
2658                 VectorNegate(surf->plane->normal, normal);
2659         else
2660                 VectorCopy(surf->plane->normal, normal);
2661         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2662         {
2663                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2664                 VectorNormalizeFast(v1);
2665                 CrossProduct(v1, normal, clipplanenormal);
2666                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2667                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2668                 if (clipdist > 0)
2669                 {
2670                         clipdist = -clipdist;
2671                         VectorMA(out, clipdist, clipplanenormal, out);
2672                 }
2673         }
2674 }
2675
2676 static msurface_t *getsurface(edict_t *ed, int surfnum)
2677 {
2678         int modelindex;
2679         model_t *model;
2680         if (!ed || ed->e->free)
2681                 return NULL;
2682         modelindex = ed->v->modelindex;
2683         if (modelindex < 1 || modelindex >= MAX_MODELS)
2684                 return NULL;
2685         model = sv.models[modelindex];
2686         if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2687                 return NULL;
2688         return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2689 }
2690
2691
2692 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2693 void PF_getsurfacenumpoints(void)
2694 {
2695         msurface_t *surf;
2696         // return 0 if no such surface
2697         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2698         {
2699                 G_FLOAT(OFS_RETURN) = 0;
2700                 return;
2701         }
2702
2703         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2704 }
2705 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2706 void PF_getsurfacepoint(void)
2707 {
2708         edict_t *ed;
2709         msurface_t *surf;
2710         int pointnum;
2711         VectorClear(G_VECTOR(OFS_RETURN));
2712         ed = G_EDICT(OFS_PARM0);
2713         if (!ed || ed->e->free)
2714                 return;
2715         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2716                 return;
2717         pointnum = G_FLOAT(OFS_PARM2);
2718         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2719                 return;
2720         // FIXME: implement rotation/scaling
2721         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2722 }
2723 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2724 void PF_getsurfacenormal(void)
2725 {
2726         msurface_t *surf;
2727         VectorClear(G_VECTOR(OFS_RETURN));
2728         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2729                 return;
2730         // FIXME: implement rotation/scaling
2731         if (surf->flags & SURF_PLANEBACK)
2732                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2733         else
2734                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2735 }
2736 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2737 void PF_getsurfacetexture(void)
2738 {
2739         msurface_t *surf;
2740         G_INT(OFS_RETURN) = 0;
2741         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2742                 return;
2743         G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2744 }
2745 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2746 void PF_getsurfacenearpoint(void)
2747 {
2748         int surfnum, best, modelindex;
2749         vec3_t clipped, p;
2750         vec_t dist, bestdist;
2751         edict_t *ed;
2752         model_t *model;
2753         msurface_t *surf;
2754         vec_t *point;
2755         G_FLOAT(OFS_RETURN) = -1;
2756         ed = G_EDICT(OFS_PARM0);
2757         point = G_VECTOR(OFS_PARM1);
2758
2759         if (!ed || ed->e->free)
2760                 return;
2761         modelindex = ed->v->modelindex;
2762         if (modelindex < 1 || modelindex >= MAX_MODELS)
2763                 return;
2764         model = sv.models[modelindex];
2765         if (!model->brushq1.numsurfaces)
2766                 return;
2767
2768         // FIXME: implement rotation/scaling
2769         VectorSubtract(point, ed->v->origin, p);
2770         best = -1;
2771         bestdist = 1000000000;
2772         for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2773         {
2774                 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2775                 dist = PlaneDiff(p, surf->plane);
2776                 dist = dist * dist;
2777                 if (dist < bestdist)
2778                 {
2779                         clippointtosurface(surf, p, clipped);
2780                         VectorSubtract(clipped, p, clipped);
2781                         dist += DotProduct(clipped, clipped);
2782                         if (dist < bestdist)
2783                         {
2784                                 best = surfnum;
2785                                 bestdist = dist;
2786                         }
2787                 }
2788         }
2789         G_FLOAT(OFS_RETURN) = best;
2790 }
2791 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2792 void PF_getsurfaceclippedpoint(void)
2793 {
2794         edict_t *ed;
2795         msurface_t *surf;
2796         vec3_t p, out;
2797         VectorClear(G_VECTOR(OFS_RETURN));
2798         ed = G_EDICT(OFS_PARM0);
2799         if (!ed || ed->e->free)
2800                 return;
2801         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2802                 return;
2803         // FIXME: implement rotation/scaling
2804         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2805         clippointtosurface(surf, p, out);
2806         // FIXME: implement rotation/scaling
2807         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2808 }
2809
2810 #define MAX_PRFILES 256
2811
2812 qfile_t *pr_files[MAX_PRFILES];
2813
2814 void PR_Files_Init(void)
2815 {
2816         memset(pr_files, 0, sizeof(pr_files));
2817 }
2818
2819 void PR_Files_CloseAll(void)
2820 {
2821         int i;
2822         for (i = 0;i < MAX_PRFILES;i++)
2823         {
2824                 if (pr_files[i])
2825                         FS_Close(pr_files[i]);
2826                 pr_files[i] = NULL;
2827         }
2828 }
2829
2830 //float(string s) stof = #81; // get numerical value from a string
2831 void PF_stof(void)
2832 {
2833         char string[STRINGTEMP_LENGTH];
2834         PF_VarString(0, string, sizeof(string));
2835         G_FLOAT(OFS_RETURN) = atof(string);
2836 }
2837
2838 //float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
2839 void PF_fopen(void)
2840 {
2841         int filenum, mode, i;
2842         char *modestring, *filename;
2843         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2844                 if (pr_files[filenum] == NULL)
2845                         break;
2846         if (filenum >= MAX_PRFILES)
2847         {
2848                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2849                 G_FLOAT(OFS_RETURN) = -2;
2850                 return;
2851         }
2852         mode = G_FLOAT(OFS_PARM1);
2853         switch(mode)
2854         {
2855         case 0: // FILE_READ
2856                 modestring = "rb";
2857                 break;
2858         case 1: // FILE_APPEND
2859                 modestring = "ab";
2860                 break;
2861         case 2: // FILE_WRITE
2862                 modestring = "wb";
2863                 break;
2864         default:
2865                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2866                 G_FLOAT(OFS_RETURN) = -3;
2867                 return;
2868         }
2869         filename = G_STRING(OFS_PARM0);
2870         // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2871         // ../ is parent directory on many platforms
2872         // // is parent directory on Amiga
2873         // / at the beginning of a path is root on unix, and parent directory on Amiga
2874         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2875         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2876         for (i = 0;filename[i];i++)
2877         {
2878                 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2879                 {
2880                         Con_Printf("PF_fopen: dangerous/confusing/annoying/non-portable filename \"%s\" not allowed. (contains control characters or // or .. or : or \\ or begins with /)\n", filename);
2881                         G_FLOAT(OFS_RETURN) = -4;
2882                         return;
2883                 }
2884         }
2885         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2886
2887         if (pr_files[filenum] == NULL && modestring == "rb")
2888                 pr_files[filenum] = FS_Open(filename, modestring, false);
2889
2890         if (pr_files[filenum] == NULL)
2891                 G_FLOAT(OFS_RETURN) = -1;
2892         else
2893                 G_FLOAT(OFS_RETURN) = filenum;
2894 }
2895
2896 //void(float fhandle) fclose = #111; // closes a file
2897 void PF_fclose(void)
2898 {
2899         int filenum = G_FLOAT(OFS_PARM0);
2900         if (filenum < 0 || filenum >= MAX_PRFILES)
2901         {
2902                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2903                 return;
2904         }
2905         if (pr_files[filenum] == NULL)
2906         {
2907                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2908                 return;
2909         }
2910         FS_Close(pr_files[filenum]);
2911         pr_files[filenum] = NULL;
2912 }
2913
2914 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2915 void PF_fgets(void)
2916 {
2917         int c, end;
2918         static char string[STRINGTEMP_LENGTH];
2919         int filenum = G_FLOAT(OFS_PARM0);
2920         if (filenum < 0 || filenum >= MAX_PRFILES)
2921         {
2922                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2923                 return;
2924         }
2925         if (pr_files[filenum] == NULL)
2926         {
2927                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2928                 return;
2929         }
2930         end = 0;
2931         for (;;)
2932         {
2933                 c = FS_Getc(pr_files[filenum]);
2934                 if (c == '\r' || c == '\n' || c < 0)
2935                         break;
2936                 if (end < STRINGTEMP_LENGTH - 1)
2937                         string[end++] = c;
2938         }
2939         string[end] = 0;
2940         // remove \n following \r
2941         if (c == '\r')
2942                 c = FS_Getc(pr_files[filenum]);
2943         if (developer.integer)
2944                 Con_Printf("fgets: %s\n", string);
2945         if (c >= 0 || end)
2946                 G_INT(OFS_RETURN) = PR_SetString(string);
2947         else
2948                 G_INT(OFS_RETURN) = 0;
2949 }
2950
2951 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2952 void PF_fputs(void)
2953 {
2954         int stringlength;
2955         char string[STRINGTEMP_LENGTH];
2956         int filenum = G_FLOAT(OFS_PARM0);
2957         if (filenum < 0 || filenum >= MAX_PRFILES)
2958         {
2959                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2960                 return;
2961         }
2962         if (pr_files[filenum] == NULL)
2963         {
2964                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2965                 return;
2966         }
2967         PF_VarString(1, string, sizeof(string));
2968         if ((stringlength = strlen(string)))
2969                 FS_Write(pr_files[filenum], string, stringlength);
2970         if (developer.integer)
2971                 Con_Printf("fputs: %s\n", string);
2972 }
2973
2974 //float(string s) strlen = #114; // returns how many characters are in a string
2975 void PF_strlen(void)
2976 {
2977         char *s;
2978         s = G_STRING(OFS_PARM0);
2979         if (s)
2980                 G_FLOAT(OFS_RETURN) = strlen(s);
2981         else
2982                 G_FLOAT(OFS_RETURN) = 0;
2983 }
2984
2985 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2986 void PF_strcat(void)
2987 {
2988         char *s = PR_GetTempString();
2989         PF_VarString(0, s, STRINGTEMP_LENGTH);
2990         G_INT(OFS_RETURN) = PR_SetString(s);
2991 }
2992
2993 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2994 void PF_substring(void)
2995 {
2996         int i, start, length;
2997         char *s, *string = PR_GetTempString();
2998         s = G_STRING(OFS_PARM0);
2999         start = G_FLOAT(OFS_PARM1);
3000         length = G_FLOAT(OFS_PARM2);
3001         if (!s)
3002                 s = "";
3003         for (i = 0;i < start && *s;i++, s++);
3004         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3005                 string[i] = *s;
3006         string[i] = 0;
3007         G_INT(OFS_RETURN) = PR_SetString(string);
3008 }
3009
3010 //vector(string s) stov = #117; // returns vector value from a string
3011 void PF_stov(void)
3012 {
3013         char string[STRINGTEMP_LENGTH];
3014         PF_VarString(0, string, sizeof(string));
3015         Math_atov(string, G_VECTOR(OFS_RETURN));
3016 }
3017
3018 //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
3019 void PF_strzone(void)
3020 {
3021         char *in, *out;
3022         in = G_STRING(OFS_PARM0);
3023         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3024         strcpy(out, in);
3025         G_INT(OFS_RETURN) = PR_SetString(out);
3026 }
3027
3028 //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
3029 void PF_strunzone(void)
3030 {
3031         Mem_Free(G_STRING(OFS_PARM0));
3032 }
3033
3034 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3035 //this function originally written by KrimZon, made shorter by LordHavoc
3036 void PF_clientcommand (void)
3037 {
3038         client_t *temp_client;
3039         int i;
3040
3041         //find client for this entity
3042         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3043         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3044         {
3045                 Con_Print("PF_clientcommand: entity is not a client\n");
3046                 return;
3047         }
3048
3049         temp_client = host_client;
3050         host_client = svs.clients + i;
3051         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3052         host_client = temp_client;
3053 }
3054
3055 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3056 //this function originally written by KrimZon, made shorter by LordHavoc
3057 //20040203: rewritten by LordHavoc (no longer uses allocations)
3058 int num_tokens = 0;
3059 char *tokens[256], tokenbuf[4096];
3060 void PF_tokenize (void)
3061 {
3062         int pos;
3063         const char *p;
3064         p = G_STRING(OFS_PARM0);
3065
3066         num_tokens = 0;
3067         pos = 0;
3068         while(COM_ParseToken(&p, false))
3069         {
3070                 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3071                         break;
3072                 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3073                         break;
3074                 tokens[num_tokens++] = tokenbuf + pos;
3075                 strcpy(tokenbuf + pos, com_token);
3076                 pos += strlen(com_token) + 1;
3077         }
3078
3079         G_FLOAT(OFS_RETURN) = num_tokens;
3080 }
3081
3082 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3083 //this function originally written by KrimZon, made shorter by LordHavoc
3084 void PF_argv (void)
3085 {
3086         int token_num = G_FLOAT(OFS_PARM0);
3087         if (token_num >= 0 && token_num < num_tokens)
3088                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3089         else
3090                 G_INT(OFS_RETURN) = PR_SetString("");
3091 }
3092
3093 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
3094 void PF_setattachment (void)
3095 {
3096         edict_t *e = G_EDICT(OFS_PARM0);
3097         edict_t *tagentity = G_EDICT(OFS_PARM1);
3098         char *tagname = G_STRING(OFS_PARM2);
3099         eval_t *v;
3100         int i, modelindex;
3101         model_t *model;
3102
3103         if (e == sv.edicts)
3104                 PF_WARNING("setattachment: can not modify world entity\n");
3105         if (e->e->free)
3106                 PF_WARNING("setattachment: can not modify free entity\n");
3107
3108         if (tagentity == NULL)
3109                 tagentity = sv.edicts;
3110
3111         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3112         if (v)
3113                 v->edict = EDICT_TO_PROG(tagentity);
3114
3115         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3116         if (v)
3117                 v->_float = 0;
3118         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3119         {
3120                 modelindex = (int)tagentity->v->modelindex;
3121                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3122                 {
3123                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3124                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3125                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3126                                                 v->_float = i + 1;
3127                         // FIXME: use a model function to get tag info (need to handle skeletal)
3128                         if (v->_float == 0 && model->alias.aliasnum_tags)
3129                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3130                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3131                                                 v->_float = i + 1;
3132                         if (v->_float == 0)
3133                                 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
3134                 }
3135                 else
3136                         Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
3137         }
3138 }
3139
3140 /////////////////////////////////////////
3141 // DP_MD3_TAGINFO extension coded by VorteX
3142
3143 //float(entity ent, string tagname) gettagindex;
3144 void PF_gettagindex (void)
3145 {
3146         edict_t *e = G_EDICT(OFS_PARM0);
3147         const char *tagname = G_STRING(OFS_PARM1);
3148         int modelindex, tagindex, i;
3149         model_t *model;
3150
3151         if (e == sv.edicts)
3152                 PF_WARNING("gettagindex: can't affect world entity\n");
3153         if (e->e->free)
3154                 PF_WARNING("gettagindex: can't affect free entity\n");
3155
3156         modelindex = (int)e->v->modelindex;
3157         if (modelindex <= 0 || modelindex > MAX_MODELS)
3158         {
3159                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3160                 return;
3161         }
3162         model = sv.models[modelindex];
3163
3164         tagindex = -1;
3165         if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3166         {
3167                 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3168                 {
3169                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3170                         {
3171                                 tagindex = i;
3172                                 break;
3173                         }
3174                 }
3175         }
3176         if (tagindex == -1)
3177         {
3178                 for (i = 0;i < model->alias.aliasnum_tags; i++)
3179                 {
3180                         if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3181                         {
3182                                 tagindex = i;
3183                                 break;
3184                         }
3185                 }
3186         }
3187         if (tagindex == -1)
3188                 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(e), tagname);
3189         G_FLOAT(OFS_RETURN) = tagindex + 1;
3190 };
3191
3192 // Warnings/errors code:
3193 // 0 - normal (everything all-right)
3194 // 1 - world entity
3195 // 2 - free entity
3196 // 3 - null or non-precached model
3197 // 4 - no tags with requested index
3198 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3199 {
3200         eval_t *val;
3201         float scale;
3202         int modelindex, tagsnum, reqframe;
3203         matrix4x4_t entitymatrix, tagmatrix;
3204         model_t *model;
3205
3206         Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3207
3208         if (ent == sv.edicts)
3209                 return 1;
3210         if (ent->e->free)
3211                 return 2;
3212
3213         modelindex = (int)ent->v->modelindex;
3214         if (modelindex <= 0 || modelindex > MAX_MODELS)
3215                 return 3;
3216
3217         model = sv.models[modelindex];
3218         tagsnum = model->alias.aliasnum_tags;
3219
3220         if (tagindex <= 0 || tagindex > tagsnum)
3221         {
3222                 if (tagsnum && tagindex) // Only appear if model has no tags or not-null tag requested
3223                         return 4;
3224                 return 0;
3225         }
3226
3227         if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3228                 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3229         else
3230                 reqframe = ent->v->frame;
3231
3232         // just reusing a temp
3233         modelindex = (tagindex - 1) + ent->v->frame*tagsnum;
3234
3235         // transform tag by its own entity matrix
3236         Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[modelindex].matrix);
3237         // FIXME: add scale parameter
3238         scale = 1;
3239         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3240         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);
3241         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3242         // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3243         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]);
3244         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]);
3245         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]);
3246         /* Optimised variant with only v_forward using
3247         out->m[0][3] = entitymatrix.m[0][3] + scale*entitymatrix.m[0][0]*tagmatrix.m[0][3];
3248         out->m[1][3] = entitymatrix.m[1][3] + scale*entitymatrix.m[1][0]*tagmatrix.m[1][3];
3249         out->m[2][3] = entitymatrix.m[2][3] + scale*entitymatrix.m[2][0]*tagmatrix.m[2][3];
3250         */
3251
3252         // additional actions for render-view entities
3253         if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3254         {// RENDER_VIEWMODEL
3255                 ent = EDICT_NUM(val->edict);
3256                 // FIXME: "circle" bug, add bobbing (cl_bob), add scale parameter
3257                 scale = 1;
3258                 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);
3259                 Matrix4x4_Concat(out, &entitymatrix, out);
3260                 out->m[0][3] = entitymatrix.m[0][3] + scale*entitymatrix.m[0][0]*out->m[0][3];
3261                 out->m[1][3] = entitymatrix.m[1][3] + scale*entitymatrix.m[1][0]*out->m[1][3];
3262                 out->m[2][3] = entitymatrix.m[2][3] + scale*entitymatrix.m[2][0]*out->m[2][3];
3263                 Con_DPrintf("SV_GetTagMatrix: returned origin is %f %f %f\n", out->m[0][3], out->m[1][3], out->m[2][3]);
3264                 return 0;
3265         }
3266         // RENDER_VIEWMODEL can't be attached by tag, right?
3267         val = GETEDICTFIELDVALUE(ent, eval_tag_entity);
3268         if (val->edict)
3269         {// DP_GFX_QUAKE3MODELTAGS
3270                 do
3271                 {
3272                         ent = EDICT_NUM(val->edict);
3273                         // FIXME: add scale parameter
3274                         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);
3275                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3276                         // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3277                         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]);
3278                         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]);
3279                         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]);
3280                 }
3281                 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3282         }
3283         return 0;
3284 }
3285
3286 //vector(entity ent, float tagindex) gettaginfo;
3287 void PF_gettaginfo (void)
3288 {
3289         edict_t *e = G_EDICT(OFS_PARM0);
3290         int tagindex = (int)G_FLOAT(OFS_PARM1);
3291         matrix4x4_t tag_matrix;
3292         int returncode;
3293
3294         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3295         Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3296
3297         switch(returncode)
3298         {
3299                 case 1:
3300                         PF_WARNING("gettagindex: can't affect world entity\n");
3301                         break;
3302                 case 2:
3303                         PF_WARNING("gettagindex: can't affect free entity\n");
3304                         break;
3305                 case 3:
3306                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3307                         break;
3308                 case 4:
3309                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3310                         break;
3311         }
3312 }
3313
3314
3315 /////////////////////////////////////////
3316 // DP_QC_FS_SEARCH extension
3317
3318 // qc fs search handling
3319 #define MAX_SEARCHES 128
3320
3321 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3322
3323 void PR_Search_Init(void)
3324 {
3325         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3326 }
3327
3328 void PR_Search_Reset(void)
3329 {
3330         int i;
3331         // reset the fssearch list
3332         for(i = 0; i < MAX_SEARCHES; i++)
3333                 if(pr_fssearchlist[i])
3334                         FS_FreeSearch(pr_fssearchlist[i]);
3335         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3336 }
3337
3338 /*
3339 =========
3340 PF_search_begin
3341
3342 float search_begin(string pattern, float caseinsensitive, float quiet)
3343 =========
3344 */
3345 void PF_search_begin(void)
3346 {
3347         int handle;
3348         char *pattern;
3349         int caseinsens, quiet;
3350
3351         pattern = G_STRING(OFS_PARM0);
3352
3353         PR_CheckEmptyString(pattern);
3354
3355         caseinsens = G_FLOAT(OFS_PARM1);
3356         quiet = G_FLOAT(OFS_PARM2);
3357         
3358         for(handle = 0; handle < MAX_SEARCHES; handle++)
3359                 if(!pr_fssearchlist[handle])
3360                         break;
3361
3362         if(handle >= MAX_SEARCHES)
3363         {
3364                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3365                 G_FLOAT(OFS_RETURN) = -2;
3366                 return;
3367         }
3368
3369         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3370                 G_FLOAT(OFS_RETURN) = -1;
3371         else
3372                 G_FLOAT(OFS_RETURN) = handle;
3373 }
3374
3375 /*
3376 =========
3377 VM_search_end
3378
3379 void    search_end(float handle)
3380 =========
3381 */
3382 void PF_search_end(void)
3383 {
3384         int handle;
3385
3386         handle = G_FLOAT(OFS_PARM0);
3387         
3388         if(handle < 0 || handle >= MAX_SEARCHES)
3389         {
3390                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3391                 return;
3392         }
3393         if(pr_fssearchlist[handle] == NULL)
3394         {
3395                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3396                 return;
3397         }
3398
3399         FS_FreeSearch(pr_fssearchlist[handle]);
3400         pr_fssearchlist[handle] = NULL;
3401 }
3402
3403 /*
3404 =========
3405 VM_search_getsize
3406
3407 float   search_getsize(float handle)
3408 =========
3409 */
3410 void PF_search_getsize(void)
3411 {
3412         int handle;
3413
3414         handle = G_FLOAT(OFS_PARM0);
3415
3416         if(handle < 0 || handle >= MAX_SEARCHES)
3417         {
3418                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3419                 return;
3420         }
3421         if(pr_fssearchlist[handle] == NULL)
3422         {
3423                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3424                 return;
3425         }
3426         
3427         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3428 }
3429
3430 /*
3431 =========
3432 VM_search_getfilename
3433
3434 string  search_getfilename(float handle, float num)
3435 =========
3436 */
3437 void PF_search_getfilename(void)
3438 {
3439         int handle, filenum;
3440         char *tmp;
3441
3442         handle = G_FLOAT(OFS_PARM0);
3443         filenum = G_FLOAT(OFS_PARM1);
3444
3445         if(handle < 0 || handle >= MAX_SEARCHES)
3446         {
3447                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3448                 return;
3449         }
3450         if(pr_fssearchlist[handle] == NULL)
3451         {
3452                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3453                 return;
3454         }
3455         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3456         {
3457                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3458                 return;
3459         }
3460         
3461         tmp = PR_GetTempString();
3462         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3463
3464         G_INT(OFS_RETURN) = PR_SetString(tmp);
3465 }
3466
3467 void PF_cvar_string (void)
3468 {
3469         char *str;
3470         cvar_t *var;
3471         char *tmp;
3472
3473         str = G_STRING(OFS_PARM0);
3474         var = Cvar_FindVar (str);
3475         if (var)
3476         {
3477                 tmp = PR_GetTempString();
3478                 strcpy(tmp, var->string);
3479         }
3480         else
3481                 tmp = "";
3482         G_INT(OFS_RETURN) = PR_SetString(tmp);
3483 }
3484
3485
3486
3487 builtin_t pr_builtin[] =
3488 {
3489 NULL,                                           // #0
3490 PF_makevectors,                         // #1 void(entity e) makevectors
3491 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3492 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3493 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3494 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3495 PF_break,                                       // #6 void() break
3496 PF_random,                                      // #7 float() random
3497 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3498 PF_normalize,                           // #9 vector(vector v) normalize
3499 PF_error,                                       // #10 void(string e) error
3500 PF_objerror,                            // #11 void(string e) objerror
3501 PF_vlen,                                        // #12 float(vector v) vlen
3502 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3503 PF_Spawn,                                       // #14 entity() spawn
3504 PF_Remove,                                      // #15 void(entity e) remove
3505 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3506 PF_checkclient,                         // #17 entity() clientlist
3507 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3508 PF_precache_sound,                      // #19 void(string s) precache_sound
3509 PF_precache_model,                      // #20 void(string s) precache_model
3510 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3511 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3512 PF_bprint,                                      // #23 void(string s) bprint
3513 PF_sprint,                                      // #24 void(entity client, string s) sprint
3514 PF_dprint,                                      // #25 void(string s) dprint
3515 PF_ftos,                                        // #26 void(string s) ftos
3516 PF_vtos,                                        // #27 void(string s) vtos
3517 PF_coredump,                            // #28 void() coredump
3518 PF_traceon,                                     // #29 void() traceon
3519 PF_traceoff,                            // #30 void() traceoff
3520 PF_eprint,                                      // #31 void(entity e) eprint
3521 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3522 NULL,                                           // #33
3523 PF_droptofloor,                         // #34 float() droptofloor
3524 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3525 PF_rint,                                        // #36 float(float v) rint
3526 PF_floor,                                       // #37 float(float v) floor
3527 PF_ceil,                                        // #38 float(float v) ceil
3528 NULL,                                           // #39
3529 PF_checkbottom,                         // #40 float(entity e) checkbottom
3530 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3531 NULL,                                           // #42
3532 PF_fabs,                                        // #43 float(float f) fabs
3533 PF_aim,                                         // #44 vector(entity e, float speed) aim
3534 PF_cvar,                                        // #45 float(string s) cvar
3535 PF_localcmd,                            // #46 void(string s) localcmd
3536 PF_nextent,                                     // #47 entity(entity e) nextent
3537 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3538 PF_changeyaw,                           // #49 void() ChangeYaw
3539 NULL,                                           // #50
3540 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3541 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3542 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3543 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3544 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3545 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3546 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3547 PF_WriteString,                         // #58 void(float to, string s) WriteString
3548 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3549 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3550 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3551 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3552 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3553 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3554 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3555 NULL,                                           // #66
3556 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3557 PF_precache_file,                       // #68 string(string s) precache_file
3558 PF_makestatic,                          // #69 void(entity e) makestatic
3559 PF_changelevel,                         // #70 void(string s) changelevel
3560 NULL,                                           // #71
3561 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3562 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3563 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3564 PF_precache_model,                      // #75 string(string s) precache_model2
3565 PF_precache_sound,                      // #76 string(string s) precache_sound2
3566 PF_precache_file,                       // #77 string(string s) precache_file2
3567 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3568 NULL,                                           // #79
3569 NULL,                                           // #80
3570 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3571 NULL,                                           // #82
3572 NULL,                                           // #83
3573 NULL,                                           // #84
3574 NULL,                                           // #85
3575 NULL,                                           // #86
3576 NULL,                                           // #87
3577 NULL,                                           // #88
3578 NULL,                                           // #89
3579 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3580 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3581 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3582 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3583 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3584 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3585 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3586 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3587 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3588 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3589 NULL,                                           // #100
3590 NULL,                                           // #101
3591 NULL,                                           // #102
3592 NULL,                                           // #103
3593 NULL,                                           // #104
3594 NULL,                                           // #105
3595 NULL,                                           // #106
3596 NULL,                                           // #107
3597 NULL,                                           // #108
3598 NULL,                                           // #109
3599 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3600 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3601 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3602 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3603 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3604 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3605 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3606 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3607 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3608 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3609 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3610 a a a a a a a a                         // #120-199
3611 a a a a a a a a a a                     // #200-299
3612 a a a a a a a a a a                     // #300-399
3613 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3614 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3615 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3616 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3617 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3618 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3619 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3620 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3621 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3622 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3623 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3624 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3625 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3626 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3627 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3628 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3629 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3630 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3631 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3632 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3633 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3634 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3635 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3636 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3637 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3638 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3639 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3640 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3641 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3642 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3643 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3644 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3645 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3646 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3647 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3648 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3649 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3650 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3651 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3652 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3653 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3654 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3655 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3656 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3657 PF_search_begin,                        // #444
3658 PF_search_end,                          // #445
3659 PF_search_getsize,                      // #446
3660 PF_search_getfilename,          // #447
3661 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3662 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3663 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3664 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3665 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3666 NULL,                                           // #453
3667 NULL,                                           // #454
3668 NULL,                                           // #455
3669 NULL,                                           // #456
3670 NULL,                                           // #457
3671 NULL,                                           // #458
3672 NULL,                                           // #459
3673 a a a a                                         // #460-499 (LordHavoc)
3674 };
3675
3676 builtin_t *pr_builtins = pr_builtin;
3677 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3678
3679 void PR_Cmd_Init(void)
3680 {
3681         pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3682         PR_Files_Init();
3683         PR_Search_Init();
3684 }
3685
3686 void PR_Cmd_Reset(void)
3687 {
3688         Mem_EmptyPool(pr_strings_mempool);
3689         PR_Search_Reset();
3690         PR_Files_CloseAll();
3691 }
3692