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