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