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