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