]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - pr_cmds.c
c387f7b15d5b9a48226c853e9e685b43a9c21e86
[xonotic/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
25
26 mempool_t *pr_strings_mempool;
27
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
33
34 static char *PR_GetTempString(void)
35 {
36         char *s;
37         s = pr_string_temp[pr_string_tempindex];
38         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
39         return s;
40 }
41
42 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
43 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
44 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
45
46
47 /*
48 ===============================================================================
49
50                                                 BUILT-IN FUNCTIONS
51
52 ===============================================================================
53 */
54
55
56 void PF_VarString(int first, char *out, int outlength)
57 {
58         int i;
59         const char *s;
60         char *outend;
61
62         outend = out + outlength - 1;
63         for (i = first;i < pr_argc && out < outend;i++)
64         {
65                 s = G_STRING((OFS_PARM0+i*3));
66                 while (out < outend && *s)
67                         *out++ = *s++;
68         }
69         *out++ = 0;
70 }
71
72 char *ENGINE_EXTENSIONS =
73 "DP_CL_LOADSKY "
74 "DP_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 int SV_GetTagIndex (edict_t *e, char *tagname)
3151 {
3152         int tagindex, i;
3153         model_t *model;
3154
3155         model = sv.models[(int)e->v->modelindex];
3156
3157         tagindex = -1;
3158         if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3159         {
3160                 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3161                 {
3162                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3163                         {
3164                                 tagindex = i;
3165                                 break;
3166                         }
3167                 }
3168         }
3169         if (tagindex == -1)
3170         {
3171                 for (i = 0;i < model->alias.aliasnum_tags; i++)
3172                 {
3173                         if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3174                         {
3175                                 tagindex = i;
3176                                 break;
3177                         }
3178                 }
3179         }
3180         return tagindex + 1;
3181 };
3182
3183 // Warnings/errors code:
3184 // 0 - normal (everything all-right)
3185 // 1 - world entity
3186 // 2 - free entity
3187 // 3 - null or non-precached model
3188 // 4 - no tags with requested index
3189 // 5 - runaway loop at attachment chain
3190 extern cvar_t cl_bob;
3191 extern cvar_t cl_bobcycle;
3192 extern cvar_t cl_bobup;
3193 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3194 {
3195         eval_t *val;
3196         int modelindex, reqtag, reqframe, attachloop;
3197         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3198         edict_t *attachent;
3199         model_t *model;
3200
3201         Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3202
3203         if (ent == sv.edicts)
3204                 return 1;
3205         if (ent->e->free)
3206                 return 2;
3207
3208         modelindex = (int)ent->v->modelindex;
3209         if (modelindex <= 0 || modelindex > MAX_MODELS)
3210                 return 3;
3211
3212         model = sv.models[modelindex];
3213         reqtag = model->alias.aliasnum_tags;
3214
3215         if (tagindex <= 0 || tagindex > reqtag)
3216         {
3217                 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3218                         return 4;
3219                 return 0;
3220         }
3221
3222         if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3223                 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3224         else
3225                 reqframe = ent->v->frame;
3226
3227         // get initial tag matrix
3228         if (tagindex)
3229         {
3230                 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3231                 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3232         }
3233         else
3234                 Matrix4x4_CreateIdentity(&tagmatrix);
3235
3236         if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict) 
3237         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3238                 attachloop = 0;
3239                 do
3240                 {
3241                         attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3242                         val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3243                         if (val->_float) 
3244                         {// got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3245                                 model = sv.models[(int)attachent->v->modelindex];
3246                                 reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3247                                 Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3248                         }
3249                         else
3250                                 Matrix4x4_CreateIdentity(&attachmatrix);
3251
3252                         // apply transformation by child entity matrix
3253                         val = GETEDICTFIELDVALUE(ent, eval_scale);
3254                         if (val->_float == 0)
3255                                 val->_float = 1;
3256                         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], val->_float);
3257                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3258                         out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3259                         out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3260                         out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);           
3261                         Matrix4x4_Copy(&tagmatrix, out);
3262
3263                         // finally transformate by matrix of tag on parent entity
3264                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3265                         out->m[0][3] = attachmatrix.m[0][3] + attachmatrix.m[0][0]*tagmatrix.m[0][3] + attachmatrix.m[0][1]*tagmatrix.m[1][3] + attachmatrix.m[0][2]*tagmatrix.m[2][3];
3266                         out->m[1][3] = attachmatrix.m[1][3] + attachmatrix.m[1][0]*tagmatrix.m[0][3] + attachmatrix.m[1][1]*tagmatrix.m[1][3] + attachmatrix.m[1][2]*tagmatrix.m[2][3];
3267                         out->m[2][3] = attachmatrix.m[2][3] + attachmatrix.m[2][0]*tagmatrix.m[0][3] + attachmatrix.m[2][1]*tagmatrix.m[1][3] + attachmatrix.m[2][2]*tagmatrix.m[2][3];         
3268                         Matrix4x4_Copy(&tagmatrix, out);
3269
3270                         ent = attachent;
3271                         attachloop += 1;
3272                         if (attachloop > 255) // prevent runaway looping
3273                                 return 5;
3274                 } 
3275                 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3276         }
3277
3278         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3279         val = GETEDICTFIELDVALUE(ent, eval_scale);
3280         if (val->_float == 0)
3281                 val->_float = 1;
3282         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3283         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], val->_float);
3284         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3285         out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3286         out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3287         out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);           
3288
3289         if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3290         {// RENDER_VIEWMODEL magic
3291                 Matrix4x4_Copy(&tagmatrix, out);
3292                 ent = EDICT_NUM(val->edict);
3293
3294                 val = GETEDICTFIELDVALUE(ent, eval_scale);
3295                 if (val->_float == 0)
3296                         val->_float = 1;
3297
3298                 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], val->_float);
3299                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3300                 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3301                 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3302                 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);           
3303
3304                 /*
3305                 // Cl_bob, ported from rendering code
3306                 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3307                 {
3308                         double bob, cycle;
3309                         // LordHavoc: this code is *weird*, but not replacable (I think it
3310                         // should be done in QC on the server, but oh well, quake is quake)
3311                         // LordHavoc: figured out bobup: the time at which the sin is at 180
3312                         // degrees (which allows lengthening or squishing the peak or valley)
3313                         cycle = sv.time/cl_bobcycle.value;
3314                         cycle -= (int)cycle;
3315                         if (cycle < cl_bobup.value)
3316                                 cycle = sin(M_PI * cycle / cl_bobup.value);
3317                         else
3318                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3319                         // bob is proportional to velocity in the xy plane
3320                         // (don't count Z, or jumping messes it up)
3321                         bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3322                         bob = bob*0.3 + bob*0.7*cycle;
3323                         out->m[2][3] += bound(-7, bob, 4);
3324                 }
3325                 */
3326         }
3327         return 0;
3328 }
3329
3330 //float(entity ent, string tagname) gettagindex;
3331
3332 void PF_gettagindex (void)
3333 {
3334         edict_t *ent = G_EDICT(OFS_PARM0);
3335         char *tag_name = G_STRING(OFS_PARM1);
3336         int modelindex, tag_index;
3337
3338         if (ent == sv.edicts)
3339                 PF_WARNING("gettagindex: can't affect world entity\n");
3340         if (ent->e->free)
3341                 PF_WARNING("gettagindex: can't affect free entity\n");
3342
3343         modelindex = (int)ent->v->modelindex;
3344         tag_index = 0;
3345         if (modelindex <= 0 || modelindex > MAX_MODELS)
3346                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3347         else
3348         {
3349                 tag_index = SV_GetTagIndex(ent, tag_name);
3350                 if (tag_index == 0)
3351                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3352         }
3353         G_FLOAT(OFS_RETURN) = tag_index;
3354 };
3355
3356 //vector(entity ent, float tagindex) gettaginfo;
3357 void PF_gettaginfo (void)
3358 {
3359         edict_t *e = G_EDICT(OFS_PARM0);
3360         int tagindex = (int)G_FLOAT(OFS_PARM1);
3361         matrix4x4_t tag_matrix;
3362         int returncode;
3363
3364         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3365         Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3366
3367         switch(returncode)
3368         {
3369                 case 1:
3370                         PF_WARNING("gettagindex: can't affect world entity\n");
3371                         break;
3372                 case 2:
3373                         PF_WARNING("gettagindex: can't affect free entity\n");
3374                         break;
3375                 case 3:
3376                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3377                         break;
3378                 case 4:
3379                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3380                         break;
3381                 case 5:
3382                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3383                         break;
3384         }
3385 }
3386
3387
3388 /////////////////////////////////////////
3389 // DP_QC_FS_SEARCH extension
3390
3391 // qc fs search handling
3392 #define MAX_SEARCHES 128
3393
3394 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3395
3396 void PR_Search_Init(void)
3397 {
3398         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3399 }
3400
3401 void PR_Search_Reset(void)
3402 {
3403         int i;
3404         // reset the fssearch list
3405         for(i = 0; i < MAX_SEARCHES; i++)
3406                 if(pr_fssearchlist[i])
3407                         FS_FreeSearch(pr_fssearchlist[i]);
3408         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3409 }
3410
3411 /*
3412 =========
3413 PF_search_begin
3414
3415 float search_begin(string pattern, float caseinsensitive, float quiet)
3416 =========
3417 */
3418 void PF_search_begin(void)
3419 {
3420         int handle;
3421         char *pattern;
3422         int caseinsens, quiet;
3423
3424         pattern = G_STRING(OFS_PARM0);
3425
3426         PR_CheckEmptyString(pattern);
3427
3428         caseinsens = G_FLOAT(OFS_PARM1);
3429         quiet = G_FLOAT(OFS_PARM2);
3430         
3431         for(handle = 0; handle < MAX_SEARCHES; handle++)
3432                 if(!pr_fssearchlist[handle])
3433                         break;
3434
3435         if(handle >= MAX_SEARCHES)
3436         {
3437                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3438                 G_FLOAT(OFS_RETURN) = -2;
3439                 return;
3440         }
3441
3442         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3443                 G_FLOAT(OFS_RETURN) = -1;
3444         else
3445                 G_FLOAT(OFS_RETURN) = handle;
3446 }
3447
3448 /*
3449 =========
3450 VM_search_end
3451
3452 void    search_end(float handle)
3453 =========
3454 */
3455 void PF_search_end(void)
3456 {
3457         int handle;
3458
3459         handle = G_FLOAT(OFS_PARM0);
3460         
3461         if(handle < 0 || handle >= MAX_SEARCHES)
3462         {
3463                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3464                 return;
3465         }
3466         if(pr_fssearchlist[handle] == NULL)
3467         {
3468                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3469                 return;
3470         }
3471
3472         FS_FreeSearch(pr_fssearchlist[handle]);
3473         pr_fssearchlist[handle] = NULL;
3474 }
3475
3476 /*
3477 =========
3478 VM_search_getsize
3479
3480 float   search_getsize(float handle)
3481 =========
3482 */
3483 void PF_search_getsize(void)
3484 {
3485         int handle;
3486
3487         handle = G_FLOAT(OFS_PARM0);
3488
3489         if(handle < 0 || handle >= MAX_SEARCHES)
3490         {
3491                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3492                 return;
3493         }
3494         if(pr_fssearchlist[handle] == NULL)
3495         {
3496                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3497                 return;
3498         }
3499         
3500         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3501 }
3502
3503 /*
3504 =========
3505 VM_search_getfilename
3506
3507 string  search_getfilename(float handle, float num)
3508 =========
3509 */
3510 void PF_search_getfilename(void)
3511 {
3512         int handle, filenum;
3513         char *tmp;
3514
3515         handle = G_FLOAT(OFS_PARM0);
3516         filenum = G_FLOAT(OFS_PARM1);
3517
3518         if(handle < 0 || handle >= MAX_SEARCHES)
3519         {
3520                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3521                 return;
3522         }
3523         if(pr_fssearchlist[handle] == NULL)
3524         {
3525                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3526                 return;
3527         }
3528         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3529         {
3530                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3531                 return;
3532         }
3533         
3534         tmp = PR_GetTempString();
3535         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3536
3537         G_INT(OFS_RETURN) = PR_SetString(tmp);
3538 }
3539
3540 void PF_cvar_string (void)
3541 {
3542         char *str;
3543         cvar_t *var;
3544         char *tmp;
3545
3546         str = G_STRING(OFS_PARM0);
3547         var = Cvar_FindVar (str);
3548         if (var)
3549         {
3550                 tmp = PR_GetTempString();
3551                 strcpy(tmp, var->string);
3552         }
3553         else
3554                 tmp = "";
3555         G_INT(OFS_RETURN) = PR_SetString(tmp);
3556 }
3557
3558 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3559 void PF_dropclient (void)
3560 {
3561         int clientnum;
3562         client_t *oldhostclient;
3563         clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3564         if (clientnum < 0 || clientnum >= svs.maxclients)
3565                 PF_WARNING("dropclient: not a client\n");
3566         if (!svs.clients[clientnum].active)
3567                 PF_WARNING("dropclient: that client slot is not connected\n");
3568         oldhostclient = host_client;
3569         host_client = svs.clients + clientnum;
3570         SV_DropClient(false);
3571         host_client = oldhostclient;
3572 }
3573
3574
3575 builtin_t pr_builtin[] =
3576 {
3577 NULL,                                           // #0
3578 PF_makevectors,                         // #1 void(entity e) makevectors
3579 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3580 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3581 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3582 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3583 PF_break,                                       // #6 void() break
3584 PF_random,                                      // #7 float() random
3585 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3586 PF_normalize,                           // #9 vector(vector v) normalize
3587 PF_error,                                       // #10 void(string e) error
3588 PF_objerror,                            // #11 void(string e) objerror
3589 PF_vlen,                                        // #12 float(vector v) vlen
3590 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3591 PF_Spawn,                                       // #14 entity() spawn
3592 PF_Remove,                                      // #15 void(entity e) remove
3593 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3594 PF_checkclient,                         // #17 entity() clientlist
3595 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3596 PF_precache_sound,                      // #19 void(string s) precache_sound
3597 PF_precache_model,                      // #20 void(string s) precache_model
3598 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3599 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3600 PF_bprint,                                      // #23 void(string s) bprint
3601 PF_sprint,                                      // #24 void(entity client, string s) sprint
3602 PF_dprint,                                      // #25 void(string s) dprint
3603 PF_ftos,                                        // #26 void(string s) ftos
3604 PF_vtos,                                        // #27 void(string s) vtos
3605 PF_coredump,                            // #28 void() coredump
3606 PF_traceon,                                     // #29 void() traceon
3607 PF_traceoff,                            // #30 void() traceoff
3608 PF_eprint,                                      // #31 void(entity e) eprint
3609 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3610 NULL,                                           // #33
3611 PF_droptofloor,                         // #34 float() droptofloor
3612 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3613 PF_rint,                                        // #36 float(float v) rint
3614 PF_floor,                                       // #37 float(float v) floor
3615 PF_ceil,                                        // #38 float(float v) ceil
3616 NULL,                                           // #39
3617 PF_checkbottom,                         // #40 float(entity e) checkbottom
3618 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3619 NULL,                                           // #42
3620 PF_fabs,                                        // #43 float(float f) fabs
3621 PF_aim,                                         // #44 vector(entity e, float speed) aim
3622 PF_cvar,                                        // #45 float(string s) cvar
3623 PF_localcmd,                            // #46 void(string s) localcmd
3624 PF_nextent,                                     // #47 entity(entity e) nextent
3625 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3626 PF_changeyaw,                           // #49 void() ChangeYaw
3627 NULL,                                           // #50
3628 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3629 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3630 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3631 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3632 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3633 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3634 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3635 PF_WriteString,                         // #58 void(float to, string s) WriteString
3636 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3637 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3638 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3639 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3640 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3641 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3642 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3643 NULL,                                           // #66
3644 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3645 PF_precache_file,                       // #68 string(string s) precache_file
3646 PF_makestatic,                          // #69 void(entity e) makestatic
3647 PF_changelevel,                         // #70 void(string s) changelevel
3648 NULL,                                           // #71
3649 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3650 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3651 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3652 PF_precache_model,                      // #75 string(string s) precache_model2
3653 PF_precache_sound,                      // #76 string(string s) precache_sound2
3654 PF_precache_file,                       // #77 string(string s) precache_file2
3655 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3656 NULL,                                           // #79
3657 NULL,                                           // #80
3658 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3659 NULL,                                           // #82
3660 NULL,                                           // #83
3661 NULL,                                           // #84
3662 NULL,                                           // #85
3663 NULL,                                           // #86
3664 NULL,                                           // #87
3665 NULL,                                           // #88
3666 NULL,                                           // #89
3667 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3668 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3669 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3670 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3671 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3672 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3673 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3674 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3675 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3676 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3677 NULL,                                           // #100
3678 NULL,                                           // #101
3679 NULL,                                           // #102
3680 NULL,                                           // #103
3681 NULL,                                           // #104
3682 NULL,                                           // #105
3683 NULL,                                           // #106
3684 NULL,                                           // #107
3685 NULL,                                           // #108
3686 NULL,                                           // #109
3687 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3688 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3689 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3690 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3691 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3692 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3693 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3694 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3695 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3696 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3697 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3698 a a a a a a a a                         // #120-199
3699 a a a a a a a a a a                     // #200-299
3700 a a a a a a a a a a                     // #300-399
3701 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3702 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3703 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3704 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3705 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3706 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3707 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3708 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3709 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3710 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3711 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3712 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3713 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3714 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3715 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3716 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3717 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3718 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3719 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3720 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3721 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3722 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3723 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3724 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3725 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3726 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3727 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3728 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3729 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3730 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3731 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3732 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3733 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3734 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3735 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3736 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3737 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3738 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3739 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3740 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3741 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3742 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3743 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3744 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3745 PF_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3746 PF_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
3747 PF_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3748 PF_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3749 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3750 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3751 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3752 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3753 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3754 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3755 NULL,                                           // #454
3756 NULL,                                           // #455
3757 NULL,                                           // #456
3758 NULL,                                           // #457
3759 NULL,                                           // #458
3760 NULL,                                           // #459
3761 a a a a                                         // #460-499 (LordHavoc)
3762 };
3763
3764 builtin_t *pr_builtins = pr_builtin;
3765 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3766
3767 void PR_Cmd_Init(void)
3768 {
3769         pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3770         PR_Files_Init();
3771         PR_Search_Init();
3772 }
3773
3774 void PR_Cmd_Reset(void)
3775 {
3776         Mem_EmptyPool(pr_strings_mempool);
3777         PR_Search_Reset();
3778         PR_Files_CloseAll();
3779 }
3780