]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - pr_cmds.c
added firstmodelbrush/nummodelbrushes fields to model struct, and moved brushes from...
[xonotic/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
25
26 mempool_t *pr_strings_mempool;
27
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
33
34 static char *PR_GetTempString(void)
35 {
36         char *s;
37         s = pr_string_temp[pr_string_tempindex];
38         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
39         return s;
40 }
41
42 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
43 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
44 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
45
46
47 /*
48 ===============================================================================
49
50                                                 BUILT-IN FUNCTIONS
51
52 ===============================================================================
53 */
54
55
56 void PF_VarString(int first, char *out, int outlength)
57 {
58         int i;
59         const char *s;
60         char *outend;
61
62         outend = out + outlength - 1;
63         for (i = first;i < pr_argc && out < outend;i++)
64         {
65                 s = G_STRING((OFS_PARM0+i*3));
66                 while (out < outend && *s)
67                         *out++ = *s++;
68         }
69         *out++ = 0;
70 }
71
72 char *ENGINE_EXTENSIONS =
73 "DP_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 *surface, vec3_t p, vec3_t out)
2604 {
2605         int i, j, k;
2606         float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2607         bestdist = 1000000000;
2608         VectorCopy(p, out);
2609         for (i = 0;i < surface->mesh.num_triangles;i++)
2610         {
2611                 // clip original point to each triangle of the surface and find the
2612                 // triangle that is closest
2613                 v[0] = surface->mesh.data_vertex3f + surface->mesh.data_element3i[i * 3 + 0] * 3;
2614                 v[1] = surface->mesh.data_vertex3f + surface->mesh.data_element3i[i * 3 + 1] * 3;
2615                 v[2] = surface->mesh.data_vertex3f + surface->mesh.data_element3i[i * 3 + 2] * 3;
2616                 TriangleNormal(v[0], v[1], v[2], facenormal);
2617                 VectorNormalize(facenormal);
2618                 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2619                 VectorMA(p, offsetdist, facenormal, temp);
2620                 for (j = 0, k = 2;j < 3;k = j, j++)
2621                 {
2622                         VectorSubtract(v[k], v[j], edgenormal);
2623                         CrossProduct(edgenormal, facenormal, sidenormal);
2624                         VectorNormalize(sidenormal);
2625                         offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2626                         if (offsetdist < 0)
2627                                 VectorMA(temp, offsetdist, sidenormal, temp);
2628                 }
2629                 dist = VectorDistance2(temp, p);
2630                 if (bestdist > dist)
2631                 {
2632                         bestdist = dist;
2633                         VectorCopy(temp, out);
2634                 }
2635         }
2636 }
2637
2638 static msurface_t *getsurface(edict_t *ed, int surfacenum)
2639 {
2640         int modelindex;
2641         model_t *model;
2642         if (!ed || ed->e->free)
2643                 return NULL;
2644         modelindex = ed->v->modelindex;
2645         if (modelindex < 1 || modelindex >= MAX_MODELS)
2646                 return NULL;
2647         model = sv.models[modelindex];
2648         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2649                 return NULL;
2650         return model->brush.data_surfaces + surfacenum + model->firstmodelsurface;
2651 }
2652
2653
2654 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2655 void PF_getsurfacenumpoints(void)
2656 {
2657         msurface_t *surface;
2658         // return 0 if no such surface
2659         if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2660         {
2661                 G_FLOAT(OFS_RETURN) = 0;
2662                 return;
2663         }
2664
2665         // note: this (incorrectly) assumes it is a simple polygon
2666         G_FLOAT(OFS_RETURN) = surface->mesh.num_vertices;
2667 }
2668 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2669 void PF_getsurfacepoint(void)
2670 {
2671         edict_t *ed;
2672         msurface_t *surface;
2673         int pointnum;
2674         VectorClear(G_VECTOR(OFS_RETURN));
2675         ed = G_EDICT(OFS_PARM0);
2676         if (!ed || ed->e->free)
2677                 return;
2678         if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2679                 return;
2680         // note: this (incorrectly) assumes it is a simple polygon
2681         pointnum = G_FLOAT(OFS_PARM2);
2682         if (pointnum < 0 || pointnum >= surface->mesh.num_vertices)
2683                 return;
2684         // FIXME: implement rotation/scaling
2685         VectorAdd(&surface->mesh.data_vertex3f[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2686 }
2687 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2688 void PF_getsurfacenormal(void)
2689 {
2690         msurface_t *surface;
2691         vec3_t normal;
2692         VectorClear(G_VECTOR(OFS_RETURN));
2693         if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2694                 return;
2695         // FIXME: implement rotation/scaling
2696         // note: this (incorrectly) assumes it is a simple polygon
2697         // note: this only returns the first triangle, so it doesn't work very
2698         // well for curved surfaces or arbitrary meshes
2699         TriangleNormal(surface->mesh.data_vertex3f, surface->mesh.data_vertex3f + 3, surface->mesh.data_vertex3f + 6, normal);
2700         VectorNormalize(normal);
2701         VectorCopy(normal, G_VECTOR(OFS_RETURN));
2702 }
2703 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2704 void PF_getsurfacetexture(void)
2705 {
2706         msurface_t *surface;
2707         G_INT(OFS_RETURN) = 0;
2708         if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2709                 return;
2710         G_INT(OFS_RETURN) = PR_SetString(surface->texture->name);
2711 }
2712 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2713 void PF_getsurfacenearpoint(void)
2714 {
2715         int surfacenum, best, modelindex;
2716         vec3_t clipped, p;
2717         vec_t dist, bestdist;
2718         edict_t *ed;
2719         model_t *model;
2720         msurface_t *surface;
2721         vec_t *point;
2722         G_FLOAT(OFS_RETURN) = -1;
2723         ed = G_EDICT(OFS_PARM0);
2724         point = G_VECTOR(OFS_PARM1);
2725
2726         if (!ed || ed->e->free)
2727                 return;
2728         modelindex = ed->v->modelindex;
2729         if (modelindex < 1 || modelindex >= MAX_MODELS)
2730                 return;
2731         model = sv.models[modelindex];
2732         if (!model->brush.num_surfaces)
2733                 return;
2734
2735         // FIXME: implement rotation/scaling
2736         VectorSubtract(point, ed->v->origin, p);
2737         best = -1;
2738         bestdist = 1000000000;
2739         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2740         {
2741                 surface = model->brush.data_surfaces + surfacenum + model->firstmodelsurface;
2742                 // first see if the nearest point on the surface's box is closer than the previous match
2743                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2744                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2745                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2746                 dist = VectorLength2(clipped);
2747                 if (dist < bestdist)
2748                 {
2749                         // it is, check the nearest point on the actual geometry
2750                         clippointtosurface(surface, p, clipped);
2751                         VectorSubtract(clipped, p, clipped);
2752                         dist += VectorLength2(clipped);
2753                         if (dist < bestdist)
2754                         {
2755                                 // that's closer too, store it as the best match
2756                                 best = surfacenum;
2757                                 bestdist = dist;
2758                         }
2759                 }
2760         }
2761         G_FLOAT(OFS_RETURN) = best;
2762 }
2763 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2764 void PF_getsurfaceclippedpoint(void)
2765 {
2766         edict_t *ed;
2767         msurface_t *surface;
2768         vec3_t p, out;
2769         VectorClear(G_VECTOR(OFS_RETURN));
2770         ed = G_EDICT(OFS_PARM0);
2771         if (!ed || ed->e->free)
2772                 return;
2773         if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2774                 return;
2775         // FIXME: implement rotation/scaling
2776         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2777         clippointtosurface(surface, p, out);
2778         // FIXME: implement rotation/scaling
2779         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2780 }
2781
2782 #define MAX_PRFILES 256
2783
2784 qfile_t *pr_files[MAX_PRFILES];
2785
2786 void PR_Files_Init(void)
2787 {
2788         memset(pr_files, 0, sizeof(pr_files));
2789 }
2790
2791 void PR_Files_CloseAll(void)
2792 {
2793         int i;
2794         for (i = 0;i < MAX_PRFILES;i++)
2795         {
2796                 if (pr_files[i])
2797                         FS_Close(pr_files[i]);
2798                 pr_files[i] = NULL;
2799         }
2800 }
2801
2802 //float(string s) stof = #81; // get numerical value from a string
2803 void PF_stof(void)
2804 {
2805         char string[STRINGTEMP_LENGTH];
2806         PF_VarString(0, string, sizeof(string));
2807         G_FLOAT(OFS_RETURN) = atof(string);
2808 }
2809
2810 //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
2811 void PF_fopen(void)
2812 {
2813         int filenum, mode;
2814         char *modestring, *filename;
2815         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2816                 if (pr_files[filenum] == NULL)
2817                         break;
2818         if (filenum >= MAX_PRFILES)
2819         {
2820                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2821                 G_FLOAT(OFS_RETURN) = -2;
2822                 return;
2823         }
2824         mode = G_FLOAT(OFS_PARM1);
2825         switch(mode)
2826         {
2827         case 0: // FILE_READ
2828                 modestring = "rb";
2829                 break;
2830         case 1: // FILE_APPEND
2831                 modestring = "ab";
2832                 break;
2833         case 2: // FILE_WRITE
2834                 modestring = "wb";
2835                 break;
2836         default:
2837                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2838                 G_FLOAT(OFS_RETURN) = -3;
2839                 return;
2840         }
2841         filename = G_STRING(OFS_PARM0);
2842         // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2843         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2844
2845         if (pr_files[filenum] == NULL && modestring == "rb")
2846                 pr_files[filenum] = FS_Open(filename, modestring, false);
2847
2848         if (pr_files[filenum] == NULL)
2849                 G_FLOAT(OFS_RETURN) = -1;
2850         else
2851                 G_FLOAT(OFS_RETURN) = filenum;
2852 }
2853
2854 //void(float fhandle) fclose = #111; // closes a file
2855 void PF_fclose(void)
2856 {
2857         int filenum = G_FLOAT(OFS_PARM0);
2858         if (filenum < 0 || filenum >= MAX_PRFILES)
2859         {
2860                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2861                 return;
2862         }
2863         if (pr_files[filenum] == NULL)
2864         {
2865                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2866                 return;
2867         }
2868         FS_Close(pr_files[filenum]);
2869         pr_files[filenum] = NULL;
2870 }
2871
2872 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2873 void PF_fgets(void)
2874 {
2875         int c, end;
2876         static char string[STRINGTEMP_LENGTH];
2877         int filenum = G_FLOAT(OFS_PARM0);
2878         if (filenum < 0 || filenum >= MAX_PRFILES)
2879         {
2880                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2881                 return;
2882         }
2883         if (pr_files[filenum] == NULL)
2884         {
2885                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2886                 return;
2887         }
2888         end = 0;
2889         for (;;)
2890         {
2891                 c = FS_Getc(pr_files[filenum]);
2892                 if (c == '\r' || c == '\n' || c < 0)
2893                         break;
2894                 if (end < STRINGTEMP_LENGTH - 1)
2895                         string[end++] = c;
2896         }
2897         string[end] = 0;
2898         // remove \n following \r
2899         if (c == '\r')
2900         {
2901                 c = FS_Getc(pr_files[filenum]);
2902                 if (c != '\n')
2903                         FS_UnGetc(pr_files[filenum], (unsigned char)c);
2904         }
2905         if (developer.integer)
2906                 Con_Printf("fgets: %s\n", string);
2907         if (c >= 0 || end)
2908                 G_INT(OFS_RETURN) = PR_SetString(string);
2909         else
2910                 G_INT(OFS_RETURN) = 0;
2911 }
2912
2913 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2914 void PF_fputs(void)
2915 {
2916         int stringlength;
2917         char string[STRINGTEMP_LENGTH];
2918         int filenum = G_FLOAT(OFS_PARM0);
2919         if (filenum < 0 || filenum >= MAX_PRFILES)
2920         {
2921                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2922                 return;
2923         }
2924         if (pr_files[filenum] == NULL)
2925         {
2926                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2927                 return;
2928         }
2929         PF_VarString(1, string, sizeof(string));
2930         if ((stringlength = strlen(string)))
2931                 FS_Write(pr_files[filenum], string, stringlength);
2932         if (developer.integer)
2933                 Con_Printf("fputs: %s\n", string);
2934 }
2935
2936 //float(string s) strlen = #114; // returns how many characters are in a string
2937 void PF_strlen(void)
2938 {
2939         char *s;
2940         s = G_STRING(OFS_PARM0);
2941         if (s)
2942                 G_FLOAT(OFS_RETURN) = strlen(s);
2943         else
2944                 G_FLOAT(OFS_RETURN) = 0;
2945 }
2946
2947 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2948 void PF_strcat(void)
2949 {
2950         char *s = PR_GetTempString();
2951         PF_VarString(0, s, STRINGTEMP_LENGTH);
2952         G_INT(OFS_RETURN) = PR_SetString(s);
2953 }
2954
2955 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2956 void PF_substring(void)
2957 {
2958         int i, start, length;
2959         char *s, *string = PR_GetTempString();
2960         s = G_STRING(OFS_PARM0);
2961         start = G_FLOAT(OFS_PARM1);
2962         length = G_FLOAT(OFS_PARM2);
2963         if (!s)
2964                 s = "";
2965         for (i = 0;i < start && *s;i++, s++);
2966         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2967                 string[i] = *s;
2968         string[i] = 0;
2969         G_INT(OFS_RETURN) = PR_SetString(string);
2970 }
2971
2972 //vector(string s) stov = #117; // returns vector value from a string
2973 void PF_stov(void)
2974 {
2975         char string[STRINGTEMP_LENGTH];
2976         PF_VarString(0, string, sizeof(string));
2977         Math_atov(string, G_VECTOR(OFS_RETURN));
2978 }
2979
2980 //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)
2981 void PF_strzone(void)
2982 {
2983         char *in, *out;
2984         in = G_STRING(OFS_PARM0);
2985         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2986         strcpy(out, in);
2987         G_INT(OFS_RETURN) = PR_SetString(out);
2988 }
2989
2990 //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!!!)
2991 void PF_strunzone(void)
2992 {
2993         Mem_Free(G_STRING(OFS_PARM0));
2994 }
2995
2996 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2997 //this function originally written by KrimZon, made shorter by LordHavoc
2998 void PF_clientcommand (void)
2999 {
3000         client_t *temp_client;
3001         int i;
3002
3003         //find client for this entity
3004         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3005         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3006         {
3007                 Con_Print("PF_clientcommand: entity is not a client\n");
3008                 return;
3009         }
3010
3011         temp_client = host_client;
3012         host_client = svs.clients + i;
3013         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3014         host_client = temp_client;
3015 }
3016
3017 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3018 //this function originally written by KrimZon, made shorter by LordHavoc
3019 //20040203: rewritten by LordHavoc (no longer uses allocations)
3020 int num_tokens = 0;
3021 char *tokens[256], tokenbuf[4096];
3022 void PF_tokenize (void)
3023 {
3024         int pos;
3025         const char *p;
3026         p = G_STRING(OFS_PARM0);
3027
3028         num_tokens = 0;
3029         pos = 0;
3030         while(COM_ParseToken(&p, false))
3031         {
3032                 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3033                         break;
3034                 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3035                         break;
3036                 tokens[num_tokens++] = tokenbuf + pos;
3037                 strcpy(tokenbuf + pos, com_token);
3038                 pos += strlen(com_token) + 1;
3039         }
3040
3041         G_FLOAT(OFS_RETURN) = num_tokens;
3042 }
3043
3044 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3045 //this function originally written by KrimZon, made shorter by LordHavoc
3046 void PF_argv (void)
3047 {
3048         int token_num = G_FLOAT(OFS_PARM0);
3049         if (token_num >= 0 && token_num < num_tokens)
3050                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3051         else
3052                 G_INT(OFS_RETURN) = PR_SetString("");
3053 }
3054
3055 //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)
3056 void PF_setattachment (void)
3057 {
3058         edict_t *e = G_EDICT(OFS_PARM0);
3059         edict_t *tagentity = G_EDICT(OFS_PARM1);
3060         char *tagname = G_STRING(OFS_PARM2);
3061         eval_t *v;
3062         int i, modelindex;
3063         model_t *model;
3064
3065         if (e == sv.edicts)
3066                 PF_WARNING("setattachment: can not modify world entity\n");
3067         if (e->e->free)
3068                 PF_WARNING("setattachment: can not modify free entity\n");
3069
3070         if (tagentity == NULL)
3071                 tagentity = sv.edicts;
3072
3073         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3074         if (v)
3075                 v->edict = EDICT_TO_PROG(tagentity);
3076
3077         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3078         if (v)
3079                 v->_float = 0;
3080         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3081         {
3082                 modelindex = (int)tagentity->v->modelindex;
3083                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3084                 {
3085                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3086                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3087                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3088                                                 v->_float = i + 1;
3089                         // FIXME: use a model function to get tag info (need to handle skeletal)
3090                         if (v->_float == 0 && model->alias.aliasnum_tags)
3091                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3092                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3093                                                 v->_float = i + 1;
3094                         if (v->_float == 0)
3095                                 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);
3096                 }
3097                 else
3098                         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));
3099         }
3100 }
3101
3102 /////////////////////////////////////////
3103 // DP_MD3_TAGINFO extension coded by VorteX
3104
3105 int SV_GetTagIndex (edict_t *e, char *tagname)
3106 {
3107         int tagindex, i;
3108         model_t *model;
3109
3110         i = e->v->modelindex;
3111         if (i < 1 || i >= MAX_MODELS)
3112                 return -1;
3113         model = sv.models[i];
3114
3115         tagindex = -1;
3116         if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3117         {
3118                 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3119                 {
3120                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3121                         {
3122                                 tagindex = i;
3123                                 break;
3124                         }
3125                 }
3126         }
3127         if (tagindex == -1)
3128         {
3129                 for (i = 0;i < model->alias.aliasnum_tags; i++)
3130                 {
3131                         if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3132                         {
3133                                 tagindex = i;
3134                                 break;
3135                         }
3136                 }
3137         }
3138         return tagindex + 1;
3139 };
3140
3141 // Warnings/errors code:
3142 // 0 - normal (everything all-right)
3143 // 1 - world entity
3144 // 2 - free entity
3145 // 3 - null or non-precached model
3146 // 4 - no tags with requested index
3147 // 5 - runaway loop at attachment chain
3148 extern cvar_t cl_bob;
3149 extern cvar_t cl_bobcycle;
3150 extern cvar_t cl_bobup;
3151 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3152 {
3153         eval_t *val;
3154         int modelindex, reqtag, reqframe, attachloop;
3155         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3156         edict_t *attachent;
3157         model_t *model;
3158
3159         Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3160
3161         if (ent == sv.edicts)
3162                 return 1;
3163         if (ent->e->free)
3164                 return 2;
3165
3166         modelindex = (int)ent->v->modelindex;
3167         if (modelindex <= 0 || modelindex > MAX_MODELS)
3168                 return 3;
3169
3170         model = sv.models[modelindex];
3171         reqtag = model->alias.aliasnum_tags;
3172
3173         if (tagindex <= 0 || tagindex > reqtag)
3174         {
3175                 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3176                         return 4;
3177                 return 0;
3178         }
3179
3180         if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3181                 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3182         else
3183                 reqframe = ent->v->frame;
3184
3185         // get initial tag matrix
3186         if (tagindex)
3187         {
3188                 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3189                 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3190         }
3191         else
3192                 Matrix4x4_CreateIdentity(&tagmatrix);
3193
3194         if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3195         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3196                 attachloop = 0;
3197                 do
3198                 {
3199                         attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3200                         val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3201                         Matrix4x4_CreateIdentity(&attachmatrix);
3202                         if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS)
3203                         {
3204                                 model = sv.models[(int)attachent->v->modelindex];
3205                                 if (val->_float < model->alias.aliasnum_tags)
3206                                 {
3207                                         // got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3208                                         model = sv.models[(int)attachent->v->modelindex];
3209                                         reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3210                                         Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3211                                 }
3212                         }
3213
3214                         // apply transformation by child entity matrix
3215                         val = GETEDICTFIELDVALUE(ent, eval_scale);
3216                         if (val->_float == 0)
3217                                 val->_float = 1;
3218                         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);
3219                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3220                         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]);
3221                         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]);
3222                         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]);
3223                         Matrix4x4_Copy(&tagmatrix, out);
3224
3225                         // finally transformate by matrix of tag on parent entity
3226                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3227                         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];
3228                         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];
3229                         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];
3230                         Matrix4x4_Copy(&tagmatrix, out);
3231
3232                         ent = attachent;
3233                         attachloop += 1;
3234                         if (attachloop > 255) // prevent runaway looping
3235                                 return 5;
3236                 }
3237                 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3238         }
3239
3240         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3241         val = GETEDICTFIELDVALUE(ent, eval_scale);
3242         if (val->_float == 0)
3243                 val->_float = 1;
3244         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3245         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);
3246         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3247         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]);
3248         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]);
3249         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]);
3250
3251         if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3252         {// RENDER_VIEWMODEL magic
3253                 Matrix4x4_Copy(&tagmatrix, out);
3254                 ent = EDICT_NUM(val->edict);
3255
3256                 val = GETEDICTFIELDVALUE(ent, eval_scale);
3257                 if (val->_float == 0)
3258                         val->_float = 1;
3259
3260                 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);
3261                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3262                 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]);
3263                 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]);
3264                 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]);
3265
3266                 /*
3267                 // Cl_bob, ported from rendering code
3268                 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3269                 {
3270                         double bob, cycle;
3271                         // LordHavoc: this code is *weird*, but not replacable (I think it
3272                         // should be done in QC on the server, but oh well, quake is quake)
3273                         // LordHavoc: figured out bobup: the time at which the sin is at 180
3274                         // degrees (which allows lengthening or squishing the peak or valley)
3275                         cycle = sv.time/cl_bobcycle.value;
3276                         cycle -= (int)cycle;
3277                         if (cycle < cl_bobup.value)
3278                                 cycle = sin(M_PI * cycle / cl_bobup.value);
3279                         else
3280                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3281                         // bob is proportional to velocity in the xy plane
3282                         // (don't count Z, or jumping messes it up)
3283                         bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3284                         bob = bob*0.3 + bob*0.7*cycle;
3285                         out->m[2][3] += bound(-7, bob, 4);
3286                 }
3287                 */
3288         }
3289         return 0;
3290 }
3291
3292 //float(entity ent, string tagname) gettagindex;
3293
3294 void PF_gettagindex (void)
3295 {
3296         edict_t *ent = G_EDICT(OFS_PARM0);
3297         char *tag_name = G_STRING(OFS_PARM1);
3298         int modelindex, tag_index;
3299
3300         if (ent == sv.edicts)
3301                 PF_WARNING("gettagindex: can't affect world entity\n");
3302         if (ent->e->free)
3303                 PF_WARNING("gettagindex: can't affect free entity\n");
3304
3305         modelindex = (int)ent->v->modelindex;
3306         tag_index = 0;
3307         if (modelindex <= 0 || modelindex > MAX_MODELS)
3308                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3309         else
3310         {
3311                 tag_index = SV_GetTagIndex(ent, tag_name);
3312                 if (tag_index == 0)
3313                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3314         }
3315         G_FLOAT(OFS_RETURN) = tag_index;
3316 };
3317
3318 //vector(entity ent, float tagindex) gettaginfo;
3319 void PF_gettaginfo (void)
3320 {
3321         edict_t *e = G_EDICT(OFS_PARM0);
3322         int tagindex = (int)G_FLOAT(OFS_PARM1);
3323         matrix4x4_t tag_matrix;
3324         int returncode;
3325
3326         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3327         Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3328
3329         switch(returncode)
3330         {
3331                 case 1:
3332                         PF_WARNING("gettagindex: can't affect world entity\n");
3333                         break;
3334                 case 2:
3335                         PF_WARNING("gettagindex: can't affect free entity\n");
3336                         break;
3337                 case 3:
3338                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3339                         break;
3340                 case 4:
3341                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3342                         break;
3343                 case 5:
3344                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3345                         break;
3346         }
3347 }
3348
3349
3350 /////////////////////////////////////////
3351 // DP_QC_FS_SEARCH extension
3352
3353 // qc fs search handling
3354 #define MAX_SEARCHES 128
3355
3356 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3357
3358 void PR_Search_Init(void)
3359 {
3360         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3361 }
3362
3363 void PR_Search_Reset(void)
3364 {
3365         int i;
3366         // reset the fssearch list
3367         for(i = 0; i < MAX_SEARCHES; i++)
3368                 if(pr_fssearchlist[i])
3369                         FS_FreeSearch(pr_fssearchlist[i]);
3370         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3371 }
3372
3373 /*
3374 =========
3375 PF_search_begin
3376
3377 float search_begin(string pattern, float caseinsensitive, float quiet)
3378 =========
3379 */
3380 void PF_search_begin(void)
3381 {
3382         int handle;
3383         char *pattern;
3384         int caseinsens, quiet;
3385
3386         pattern = G_STRING(OFS_PARM0);
3387
3388         PR_CheckEmptyString(pattern);
3389
3390         caseinsens = G_FLOAT(OFS_PARM1);
3391         quiet = G_FLOAT(OFS_PARM2);
3392
3393         for(handle = 0; handle < MAX_SEARCHES; handle++)
3394                 if(!pr_fssearchlist[handle])
3395                         break;
3396
3397         if(handle >= MAX_SEARCHES)
3398         {
3399                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3400                 G_FLOAT(OFS_RETURN) = -2;
3401                 return;
3402         }
3403
3404         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3405                 G_FLOAT(OFS_RETURN) = -1;
3406         else
3407                 G_FLOAT(OFS_RETURN) = handle;
3408 }
3409
3410 /*
3411 =========
3412 VM_search_end
3413
3414 void    search_end(float handle)
3415 =========
3416 */
3417 void PF_search_end(void)
3418 {
3419         int handle;
3420
3421         handle = G_FLOAT(OFS_PARM0);
3422
3423         if(handle < 0 || handle >= MAX_SEARCHES)
3424         {
3425                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3426                 return;
3427         }
3428         if(pr_fssearchlist[handle] == NULL)
3429         {
3430                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3431                 return;
3432         }
3433
3434         FS_FreeSearch(pr_fssearchlist[handle]);
3435         pr_fssearchlist[handle] = NULL;
3436 }
3437
3438 /*
3439 =========
3440 VM_search_getsize
3441
3442 float   search_getsize(float handle)
3443 =========
3444 */
3445 void PF_search_getsize(void)
3446 {
3447         int handle;
3448
3449         handle = G_FLOAT(OFS_PARM0);
3450
3451         if(handle < 0 || handle >= MAX_SEARCHES)
3452         {
3453                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3454                 return;
3455         }
3456         if(pr_fssearchlist[handle] == NULL)
3457         {
3458                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3459                 return;
3460         }
3461
3462         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3463 }
3464
3465 /*
3466 =========
3467 VM_search_getfilename
3468
3469 string  search_getfilename(float handle, float num)
3470 =========
3471 */
3472 void PF_search_getfilename(void)
3473 {
3474         int handle, filenum;
3475         char *tmp;
3476
3477         handle = G_FLOAT(OFS_PARM0);
3478         filenum = G_FLOAT(OFS_PARM1);
3479
3480         if(handle < 0 || handle >= MAX_SEARCHES)
3481         {
3482                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3483                 return;
3484         }
3485         if(pr_fssearchlist[handle] == NULL)
3486         {
3487                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3488                 return;
3489         }
3490         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3491         {
3492                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3493                 return;
3494         }
3495
3496         tmp = PR_GetTempString();
3497         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3498
3499         G_INT(OFS_RETURN) = PR_SetString(tmp);
3500 }
3501
3502 void PF_cvar_string (void)
3503 {
3504         char *str;
3505         cvar_t *var;
3506         char *tmp;
3507
3508         str = G_STRING(OFS_PARM0);
3509         var = Cvar_FindVar (str);
3510         if (var)
3511         {
3512                 tmp = PR_GetTempString();
3513                 strcpy(tmp, var->string);
3514         }
3515         else
3516                 tmp = "";
3517         G_INT(OFS_RETURN) = PR_SetString(tmp);
3518 }
3519
3520 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3521 void PF_dropclient (void)
3522 {
3523         int clientnum;
3524         client_t *oldhostclient;
3525         clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3526         if (clientnum < 0 || clientnum >= svs.maxclients)
3527                 PF_WARNING("dropclient: not a client\n");
3528         if (!svs.clients[clientnum].active)
3529                 PF_WARNING("dropclient: that client slot is not connected\n");
3530         oldhostclient = host_client;
3531         host_client = svs.clients + clientnum;
3532         SV_DropClient(false);
3533         host_client = oldhostclient;
3534 }
3535
3536 //entity() spawnclient (DP_SV_BOTCLIENT)
3537 void PF_spawnclient (void)
3538 {
3539         int i;
3540         edict_t *ed;
3541         pr_xfunction->builtinsprofile += 2;
3542         ed = sv.edicts;
3543         for (i = 0;i < svs.maxclients;i++)
3544         {
3545                 if (!svs.clients[i].active)
3546                 {
3547                         pr_xfunction->builtinsprofile += 100;
3548                         SV_ConnectClient (i, NULL);
3549                         ed = EDICT_NUM(i + 1);
3550                         break;
3551                 }
3552         }
3553         RETURN_EDICT(ed);
3554 }
3555
3556 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3557 void PF_clienttype (void)
3558 {
3559         int clientnum;
3560         clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3561         if (clientnum < 0 || clientnum >= svs.maxclients)
3562                 G_FLOAT(OFS_RETURN) = 3;
3563         else if (!svs.clients[clientnum].active)
3564                 G_FLOAT(OFS_RETURN) = 0;
3565         else if (svs.clients[clientnum].netconnection)
3566                 G_FLOAT(OFS_RETURN) = 1;
3567         else
3568                 G_FLOAT(OFS_RETURN) = 2;
3569 }
3570
3571 builtin_t pr_builtin[] =
3572 {
3573 NULL,                                           // #0
3574 PF_makevectors,                         // #1 void(entity e) makevectors
3575 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3576 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3577 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3578 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3579 PF_break,                                       // #6 void() break
3580 PF_random,                                      // #7 float() random
3581 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3582 PF_normalize,                           // #9 vector(vector v) normalize
3583 PF_error,                                       // #10 void(string e) error
3584 PF_objerror,                            // #11 void(string e) objerror
3585 PF_vlen,                                        // #12 float(vector v) vlen
3586 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3587 PF_Spawn,                                       // #14 entity() spawn
3588 PF_Remove,                                      // #15 void(entity e) remove
3589 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3590 PF_checkclient,                         // #17 entity() clientlist
3591 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3592 PF_precache_sound,                      // #19 void(string s) precache_sound
3593 PF_precache_model,                      // #20 void(string s) precache_model
3594 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3595 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3596 PF_bprint,                                      // #23 void(string s) bprint
3597 PF_sprint,                                      // #24 void(entity client, string s) sprint
3598 PF_dprint,                                      // #25 void(string s) dprint
3599 PF_ftos,                                        // #26 void(string s) ftos
3600 PF_vtos,                                        // #27 void(string s) vtos
3601 PF_coredump,                            // #28 void() coredump
3602 PF_traceon,                                     // #29 void() traceon
3603 PF_traceoff,                            // #30 void() traceoff
3604 PF_eprint,                                      // #31 void(entity e) eprint
3605 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3606 NULL,                                           // #33
3607 PF_droptofloor,                         // #34 float() droptofloor
3608 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3609 PF_rint,                                        // #36 float(float v) rint
3610 PF_floor,                                       // #37 float(float v) floor
3611 PF_ceil,                                        // #38 float(float v) ceil
3612 NULL,                                           // #39
3613 PF_checkbottom,                         // #40 float(entity e) checkbottom
3614 PF_pointcontents,                       // #41 float(vector v) pointcontents
3615 NULL,                                           // #42
3616 PF_fabs,                                        // #43 float(float f) fabs
3617 PF_aim,                                         // #44 vector(entity e, float speed) aim
3618 PF_cvar,                                        // #45 float(string s) cvar
3619 PF_localcmd,                            // #46 void(string s) localcmd
3620 PF_nextent,                                     // #47 entity(entity e) nextent
3621 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3622 PF_changeyaw,                           // #49 void() ChangeYaw
3623 NULL,                                           // #50
3624 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3625 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3626 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3627 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3628 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3629 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3630 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3631 PF_WriteString,                         // #58 void(float to, string s) WriteString
3632 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3633 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3634 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3635 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3636 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3637 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3638 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3639 NULL,                                           // #66
3640 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3641 PF_precache_file,                       // #68 string(string s) precache_file
3642 PF_makestatic,                          // #69 void(entity e) makestatic
3643 PF_changelevel,                         // #70 void(string s) changelevel
3644 NULL,                                           // #71
3645 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3646 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3647 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3648 PF_precache_model,                      // #75 string(string s) precache_model2
3649 PF_precache_sound,                      // #76 string(string s) precache_sound2
3650 PF_precache_file,                       // #77 string(string s) precache_file2
3651 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3652 NULL,                                           // #79
3653 NULL,                                           // #80
3654 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3655 NULL,                                           // #82
3656 NULL,                                           // #83
3657 NULL,                                           // #84
3658 NULL,                                           // #85
3659 NULL,                                           // #86
3660 NULL,                                           // #87
3661 NULL,                                           // #88
3662 NULL,                                           // #89
3663 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3664 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3665 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3666 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3667 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3668 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3669 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3670 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3671 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3672 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3673 NULL,                                           // #100
3674 NULL,                                           // #101
3675 NULL,                                           // #102
3676 NULL,                                           // #103
3677 NULL,                                           // #104
3678 NULL,                                           // #105
3679 NULL,                                           // #106
3680 NULL,                                           // #107
3681 NULL,                                           // #108
3682 NULL,                                           // #109
3683 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3684 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3685 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3686 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3687 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3688 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3689 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3690 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3691 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3692 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3693 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3694 a a a a a a a a                         // #120-199
3695 a a a a a a a a a a                     // #200-299
3696 a a a a a a a a a a                     // #300-399
3697 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3698 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3699 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3700 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3701 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3702 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3703 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3704 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3705 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3706 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3707 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3708 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3709 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3710 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3711 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3712 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3713 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3714 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3715 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3716 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3717 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3718 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3719 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3720 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3721 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3722 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3723 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3724 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3725 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3726 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3727 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3728 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3729 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3730 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3731 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3732 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3733 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3734 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3735 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3736 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3737 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3738 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3739 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3740 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3741 PF_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3742 PF_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
3743 PF_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3744 PF_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3745 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3746 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3747 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3748 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3749 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3750 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3751 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3752 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3753 NULL,                                           // #456
3754 NULL,                                           // #457
3755 NULL,                                           // #458
3756 NULL,                                           // #459
3757 a a a a                                         // #460-499 (LordHavoc)
3758 };
3759
3760 builtin_t *pr_builtins = pr_builtin;
3761 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3762
3763 void PR_Cmd_Init(void)
3764 {
3765         pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3766         PR_Files_Init();
3767         PR_Search_Init();
3768 }
3769
3770 void PR_Cmd_Shutdown(void)
3771 {
3772         Mem_FreePool (&pr_strings_mempool);
3773 }
3774
3775 void PR_Cmd_Reset(void)
3776 {
3777         Mem_EmptyPool(pr_strings_mempool);
3778         PR_Search_Reset();
3779         PR_Files_CloseAll();
3780 }
3781