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