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