]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
clear sounds before shutting down
[divverent/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
25
26 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
27 #define STRINGTEMP_BUFFERS 16
28 #define STRINGTEMP_LENGTH 4096
29 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
30 static int pr_string_tempindex = 0;
31
32 static char *PR_GetTempString(void)
33 {
34         char *s;
35         s = pr_string_temp[pr_string_tempindex];
36         pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
37         return s;
38 }
39
40 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
41 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
42 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
43
44
45 /*
46 ===============================================================================
47
48                                                 BUILT-IN FUNCTIONS
49
50 ===============================================================================
51 */
52
53
54 void PF_VarString(int first, char *out, int outlength)
55 {
56         int i;
57         const char *s;
58         char *outend;
59
60         outend = out + outlength - 1;
61         for (i = first;i < pr_argc && out < outend;i++)
62         {
63                 s = G_STRING((OFS_PARM0+i*3));
64                 while (out < outend && *s)
65                         *out++ = *s++;
66         }
67         *out++ = 0;
68 }
69
70 char *ENGINE_EXTENSIONS =
71 "DP_BUTTONCHAT "
72 "DP_BUTTONUSE "
73 "DP_CL_LOADSKY "
74 "DP_CON_SET "
75 "DP_CON_SETA "
76 "DP_CON_STARTMAP "
77 "DP_EF_ADDITIVE "
78 "DP_EF_BLUE "
79 "DP_EF_FLAME "
80 "DP_EF_FULLBRIGHT "
81 "DP_EF_NODEPTHTEST "
82 "DP_EF_NODRAW "
83 "DP_EF_NOSHADOW "
84 "DP_EF_RED "
85 "DP_EF_STARDUST "
86 "DP_ENT_ALPHA "
87 "DP_ENT_CUSTOMCOLORMAP "
88 "DP_ENT_EXTERIORMODELTOCLIENT "
89 "DP_ENT_GLOW "
90 "DP_ENT_LOWPRECISION "
91 "DP_ENT_SCALE "
92 "DP_ENT_VIEWMODEL "
93 "DP_GFX_EXTERNALTEXTURES "
94 "DP_GFX_FOG "
95 "DP_GFX_QUAKE3MODELTAGS "
96 "DP_GFX_SKINFILES "
97 "DP_GFX_SKYBOX "
98 "DP_HALFLIFE_MAP "
99 "DP_HALFLIFE_MAP_CVAR "
100 "DP_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 + 1);
1043         mins[1] = org[1] - (radius + 1);
1044         mins[2] = org[2] - (radius + 1);
1045         maxs[0] = org[0] + (radius + 1);
1046         maxs[1] = org[1] + (radius + 1);
1047         maxs[2] = org[2] + (radius + 1);
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                 // Quake did not return non-solid entities but darkplaces does
1060                 // (note: this is the reason you can't blow up fallen zombies)
1061                 if (ent->v->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1062                         continue;
1063                 // LordHavoc: compare against bounding box rather than center so it
1064                 // doesn't miss large objects, and use DotProduct instead of Length
1065                 // for a major speedup
1066                 VectorSubtract(org, ent->v->origin, eorg);
1067                 if (sv_gameplayfix_findradiusdistancetobox.integer)
1068                 {
1069                         eorg[0] -= bound(ent->v->mins[0], eorg[0], ent->v->maxs[0]);
1070                         eorg[1] -= bound(ent->v->mins[1], eorg[1], ent->v->maxs[1]);
1071                         eorg[2] -= bound(ent->v->mins[2], eorg[2], ent->v->maxs[2]);
1072                 }
1073                 else
1074                         VectorMAMAM(1, eorg, 0.5f, ent->v->mins, 0.5f, ent->v->maxs, eorg);
1075                 if (DotProduct(eorg, eorg) < radius2)
1076                 {
1077                         ent->v->chain = EDICT_TO_PROG(chain);
1078                         chain = ent;
1079                 }
1080         }
1081
1082         RETURN_EDICT(chain);
1083 }
1084
1085
1086 /*
1087 =========
1088 PF_dprint
1089 =========
1090 */
1091 void PF_dprint (void)
1092 {
1093         char string[STRINGTEMP_LENGTH];
1094         if (developer.integer)
1095         {
1096                 PF_VarString(0, string, sizeof(string));
1097                 Con_Print(string);
1098         }
1099 }
1100
1101 void PF_ftos (void)
1102 {
1103         float v;
1104         char *s;
1105         v = G_FLOAT(OFS_PARM0);
1106
1107         s = PR_GetTempString();
1108         if ((float)((int)v) == v)
1109                 sprintf(s, "%i", (int)v);
1110         else
1111                 sprintf(s, "%f", v);
1112         G_INT(OFS_RETURN) = PR_SetString(s);
1113 }
1114
1115 void PF_fabs (void)
1116 {
1117         float   v;
1118         v = G_FLOAT(OFS_PARM0);
1119         G_FLOAT(OFS_RETURN) = fabs(v);
1120 }
1121
1122 void PF_vtos (void)
1123 {
1124         char *s;
1125         s = PR_GetTempString();
1126         sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1127         G_INT(OFS_RETURN) = PR_SetString(s);
1128 }
1129
1130 void PF_etos (void)
1131 {
1132         char *s;
1133         s = PR_GetTempString();
1134         sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1135         G_INT(OFS_RETURN) = PR_SetString(s);
1136 }
1137
1138 void PF_Spawn (void)
1139 {
1140         edict_t *ed;
1141         pr_xfunction->builtinsprofile += 20;
1142         ed = ED_Alloc();
1143         RETURN_EDICT(ed);
1144 }
1145
1146 void PF_Remove (void)
1147 {
1148         edict_t *ed;
1149         pr_xfunction->builtinsprofile += 20;
1150
1151         ed = G_EDICT(OFS_PARM0);
1152         if (ed == sv.edicts)
1153                 PF_WARNING("remove: tried to remove world\n");
1154         if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1155                 PF_WARNING("remove: tried to remove a client\n");
1156         // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1157         if (ed->e->free && developer.integer)
1158                 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1159         ED_Free (ed);
1160 }
1161
1162
1163 // entity (entity start, .string field, string match) find = #5;
1164 void PF_Find (void)
1165 {
1166         int             e;
1167         int             f;
1168         char    *s, *t;
1169         edict_t *ed;
1170
1171         e = G_EDICTNUM(OFS_PARM0);
1172         f = G_INT(OFS_PARM1);
1173         s = G_STRING(OFS_PARM2);
1174         if (!s || !s[0])
1175         {
1176                 RETURN_EDICT(sv.edicts);
1177                 return;
1178         }
1179
1180         for (e++ ; e < sv.num_edicts ; e++)
1181         {
1182                 pr_xfunction->builtinsprofile++;
1183                 ed = EDICT_NUM(e);
1184                 if (ed->e->free)
1185                         continue;
1186                 t = E_STRING(ed,f);
1187                 if (!t)
1188                         continue;
1189                 if (!strcmp(t,s))
1190                 {
1191                         RETURN_EDICT(ed);
1192                         return;
1193                 }
1194         }
1195
1196         RETURN_EDICT(sv.edicts);
1197 }
1198
1199 // LordHavoc: added this for searching float, int, and entity reference fields
1200 void PF_FindFloat (void)
1201 {
1202         int             e;
1203         int             f;
1204         float   s;
1205         edict_t *ed;
1206
1207         e = G_EDICTNUM(OFS_PARM0);
1208         f = G_INT(OFS_PARM1);
1209         s = G_FLOAT(OFS_PARM2);
1210
1211         for (e++ ; e < sv.num_edicts ; e++)
1212         {
1213                 pr_xfunction->builtinsprofile++;
1214                 ed = EDICT_NUM(e);
1215                 if (ed->e->free)
1216                         continue;
1217                 if (E_FLOAT(ed,f) == s)
1218                 {
1219                         RETURN_EDICT(ed);
1220                         return;
1221                 }
1222         }
1223
1224         RETURN_EDICT(sv.edicts);
1225 }
1226
1227 // chained search for strings in entity fields
1228 // entity(.string field, string match) findchain = #402;
1229 void PF_findchain (void)
1230 {
1231         int             i;
1232         int             f;
1233         char    *s, *t;
1234         edict_t *ent, *chain;
1235
1236         chain = (edict_t *)sv.edicts;
1237
1238         f = G_INT(OFS_PARM0);
1239         s = G_STRING(OFS_PARM1);
1240         if (!s || !s[0])
1241         {
1242                 RETURN_EDICT(sv.edicts);
1243                 return;
1244         }
1245
1246         ent = NEXT_EDICT(sv.edicts);
1247         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1248         {
1249                 pr_xfunction->builtinsprofile++;
1250                 if (ent->e->free)
1251                         continue;
1252                 t = E_STRING(ent,f);
1253                 if (!t)
1254                         continue;
1255                 if (strcmp(t,s))
1256                         continue;
1257
1258                 ent->v->chain = EDICT_TO_PROG(chain);
1259                 chain = ent;
1260         }
1261
1262         RETURN_EDICT(chain);
1263 }
1264
1265 // LordHavoc: chained search for float, int, and entity reference fields
1266 // entity(.string field, float match) findchainfloat = #403;
1267 void PF_findchainfloat (void)
1268 {
1269         int             i;
1270         int             f;
1271         float   s;
1272         edict_t *ent, *chain;
1273
1274         chain = (edict_t *)sv.edicts;
1275
1276         f = G_INT(OFS_PARM0);
1277         s = G_FLOAT(OFS_PARM1);
1278
1279         ent = NEXT_EDICT(sv.edicts);
1280         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1281         {
1282                 pr_xfunction->builtinsprofile++;
1283                 if (ent->e->free)
1284                         continue;
1285                 if (E_FLOAT(ent,f) != s)
1286                         continue;
1287
1288                 ent->v->chain = EDICT_TO_PROG(chain);
1289                 chain = ent;
1290         }
1291
1292         RETURN_EDICT(chain);
1293 }
1294
1295 // LordHavoc: search for flags in float fields
1296 void PF_findflags (void)
1297 {
1298         int             e;
1299         int             f;
1300         int             s;
1301         edict_t *ed;
1302
1303         e = G_EDICTNUM(OFS_PARM0);
1304         f = G_INT(OFS_PARM1);
1305         s = (int)G_FLOAT(OFS_PARM2);
1306
1307         for (e++ ; e < sv.num_edicts ; e++)
1308         {
1309                 pr_xfunction->builtinsprofile++;
1310                 ed = EDICT_NUM(e);
1311                 if (ed->e->free)
1312                         continue;
1313                 if ((int)E_FLOAT(ed,f) & s)
1314                 {
1315                         RETURN_EDICT(ed);
1316                         return;
1317                 }
1318         }
1319
1320         RETURN_EDICT(sv.edicts);
1321 }
1322
1323 // LordHavoc: chained search for flags in float fields
1324 void PF_findchainflags (void)
1325 {
1326         int             i;
1327         int             f;
1328         int             s;
1329         edict_t *ent, *chain;
1330
1331         chain = (edict_t *)sv.edicts;
1332
1333         f = G_INT(OFS_PARM0);
1334         s = (int)G_FLOAT(OFS_PARM1);
1335
1336         ent = NEXT_EDICT(sv.edicts);
1337         for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1338         {
1339                 pr_xfunction->builtinsprofile++;
1340                 if (ent->e->free)
1341                         continue;
1342                 if (!((int)E_FLOAT(ent,f) & s))
1343                         continue;
1344
1345                 ent->v->chain = EDICT_TO_PROG(chain);
1346                 chain = ent;
1347         }
1348
1349         RETURN_EDICT(chain);
1350 }
1351
1352 void PR_CheckEmptyString (char *s)
1353 {
1354         if (s[0] <= ' ')
1355                 PF_ERROR("Bad string");
1356 }
1357
1358 void PF_precache_file (void)
1359 {       // precache_file is only used to copy files with qcc, it does nothing
1360         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1361 }
1362
1363
1364 void PF_precache_sound (void)
1365 {
1366         SV_SoundIndex(G_STRING(OFS_PARM0), 2);
1367         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1368 }
1369
1370 void PF_precache_model (void)
1371 {
1372         SV_ModelIndex(G_STRING(OFS_PARM0), 2);
1373         G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1374 }
1375
1376
1377 void PF_coredump (void)
1378 {
1379         ED_PrintEdicts ();
1380 }
1381
1382 void PF_traceon (void)
1383 {
1384         pr_trace = true;
1385 }
1386
1387 void PF_traceoff (void)
1388 {
1389         pr_trace = false;
1390 }
1391
1392 void PF_eprint (void)
1393 {
1394         ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1395 }
1396
1397 /*
1398 ===============
1399 PF_walkmove
1400
1401 float(float yaw, float dist) walkmove
1402 ===============
1403 */
1404 void PF_walkmove (void)
1405 {
1406         edict_t *ent;
1407         float   yaw, dist;
1408         vec3_t  move;
1409         mfunction_t     *oldf;
1410         int     oldself;
1411
1412         // assume failure if it returns early
1413         G_FLOAT(OFS_RETURN) = 0;
1414
1415         ent = PROG_TO_EDICT(pr_global_struct->self);
1416         if (ent == sv.edicts)
1417                 PF_WARNING("walkmove: can not modify world entity\n");
1418         if (ent->e->free)
1419                 PF_WARNING("walkmove: can not modify free entity\n");
1420         yaw = G_FLOAT(OFS_PARM0);
1421         dist = G_FLOAT(OFS_PARM1);
1422
1423         if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1424                 return;
1425
1426         yaw = yaw*M_PI*2 / 360;
1427
1428         move[0] = cos(yaw)*dist;
1429         move[1] = sin(yaw)*dist;
1430         move[2] = 0;
1431
1432 // save program state, because SV_movestep may call other progs
1433         oldf = pr_xfunction;
1434         oldself = pr_global_struct->self;
1435
1436         G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1437
1438
1439 // restore program state
1440         pr_xfunction = oldf;
1441         pr_global_struct->self = oldself;
1442 }
1443
1444 /*
1445 ===============
1446 PF_droptofloor
1447
1448 void() droptofloor
1449 ===============
1450 */
1451 void PF_droptofloor (void)
1452 {
1453         edict_t         *ent;
1454         vec3_t          end;
1455         trace_t         trace;
1456
1457         // assume failure if it returns early
1458         G_FLOAT(OFS_RETURN) = 0;
1459
1460         ent = PROG_TO_EDICT(pr_global_struct->self);
1461         if (ent == sv.edicts)
1462                 PF_WARNING("droptofloor: can not modify world entity\n");
1463         if (ent->e->free)
1464                 PF_WARNING("droptofloor: can not modify free entity\n");
1465
1466         VectorCopy (ent->v->origin, end);
1467         end[2] -= 256;
1468
1469         trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1470
1471         if (trace.fraction != 1)
1472         {
1473                 VectorCopy (trace.endpos, ent->v->origin);
1474                 SV_LinkEdict (ent, false);
1475                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1476                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1477                 G_FLOAT(OFS_RETURN) = 1;
1478                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1479                 ent->e->suspendedinairflag = true;
1480         }
1481 }
1482
1483 /*
1484 ===============
1485 PF_lightstyle
1486
1487 void(float style, string value) lightstyle
1488 ===============
1489 */
1490 void PF_lightstyle (void)
1491 {
1492         int             style;
1493         char    *val;
1494         client_t        *client;
1495         int                     j;
1496
1497         style = G_FLOAT(OFS_PARM0);
1498         val = G_STRING(OFS_PARM1);
1499
1500 // change the string in sv
1501         sv.lightstyles[style] = val;
1502
1503 // send message to all clients on this server
1504         if (sv.state != ss_active)
1505                 return;
1506
1507         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1508         {
1509                 if (client->active)
1510                 {
1511                         MSG_WriteChar (&client->message, svc_lightstyle);
1512                         MSG_WriteChar (&client->message,style);
1513                         MSG_WriteString (&client->message, val);
1514                 }
1515         }
1516 }
1517
1518 void PF_rint (void)
1519 {
1520         float   f;
1521         f = G_FLOAT(OFS_PARM0);
1522         if (f > 0)
1523                 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1524         else
1525                 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1526 }
1527 void PF_floor (void)
1528 {
1529         G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1530 }
1531 void PF_ceil (void)
1532 {
1533         G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1534 }
1535
1536
1537 /*
1538 =============
1539 PF_checkbottom
1540 =============
1541 */
1542 void PF_checkbottom (void)
1543 {
1544         G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1545 }
1546
1547 /*
1548 =============
1549 PF_pointcontents
1550 =============
1551 */
1552 void PF_pointcontents (void)
1553 {
1554         G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1555 }
1556
1557 /*
1558 =============
1559 PF_nextent
1560
1561 entity nextent(entity)
1562 =============
1563 */
1564 void PF_nextent (void)
1565 {
1566         int             i;
1567         edict_t *ent;
1568
1569         i = G_EDICTNUM(OFS_PARM0);
1570         while (1)
1571         {
1572                 pr_xfunction->builtinsprofile++;
1573                 i++;
1574                 if (i == sv.num_edicts)
1575                 {
1576                         RETURN_EDICT(sv.edicts);
1577                         return;
1578                 }
1579                 ent = EDICT_NUM(i);
1580                 if (!ent->e->free)
1581                 {
1582                         RETURN_EDICT(ent);
1583                         return;
1584                 }
1585         }
1586 }
1587
1588 /*
1589 =============
1590 PF_aim
1591
1592 Pick a vector for the player to shoot along
1593 vector aim(entity, missilespeed)
1594 =============
1595 */
1596 void PF_aim (void)
1597 {
1598         edict_t *ent, *check, *bestent;
1599         vec3_t  start, dir, end, bestdir;
1600         int             i, j;
1601         trace_t tr;
1602         float   dist, bestdist;
1603         float   speed;
1604
1605         // assume failure if it returns early
1606         VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1607         // if sv_aim is so high it can't possibly accept anything, skip out early
1608         if (sv_aim.value >= 1)
1609                 return;
1610
1611         ent = G_EDICT(OFS_PARM0);
1612         if (ent == sv.edicts)
1613                 PF_WARNING("aim: can not use world entity\n");
1614         if (ent->e->free)
1615                 PF_WARNING("aim: can not use free entity\n");
1616         speed = G_FLOAT(OFS_PARM1);
1617
1618         VectorCopy (ent->v->origin, start);
1619         start[2] += 20;
1620
1621 // try sending a trace straight
1622         VectorCopy (pr_global_struct->v_forward, dir);
1623         VectorMA (start, 2048, dir, end);
1624         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1625         if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1626         && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1627         {
1628                 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1629                 return;
1630         }
1631
1632
1633 // try all possible entities
1634         VectorCopy (dir, bestdir);
1635         bestdist = sv_aim.value;
1636         bestent = NULL;
1637
1638         check = NEXT_EDICT(sv.edicts);
1639         for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1640         {
1641                 pr_xfunction->builtinsprofile++;
1642                 if (check->v->takedamage != DAMAGE_AIM)
1643                         continue;
1644                 if (check == ent)
1645                         continue;
1646                 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1647                         continue;       // don't aim at teammate
1648                 for (j=0 ; j<3 ; j++)
1649                         end[j] = check->v->origin[j]
1650                         + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1651                 VectorSubtract (end, start, dir);
1652                 VectorNormalize (dir);
1653                 dist = DotProduct (dir, pr_global_struct->v_forward);
1654                 if (dist < bestdist)
1655                         continue;       // to far to turn
1656                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1657                 if (tr.ent == check)
1658                 {       // can shoot at this one
1659                         bestdist = dist;
1660                         bestent = check;
1661                 }
1662         }
1663
1664         if (bestent)
1665         {
1666                 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1667                 dist = DotProduct (dir, pr_global_struct->v_forward);
1668                 VectorScale (pr_global_struct->v_forward, dist, end);
1669                 end[2] = dir[2];
1670                 VectorNormalize (end);
1671                 VectorCopy (end, G_VECTOR(OFS_RETURN));
1672         }
1673         else
1674         {
1675                 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1676         }
1677 }
1678
1679 /*
1680 ==============
1681 PF_changeyaw
1682
1683 This was a major timewaster in progs, so it was converted to C
1684 ==============
1685 */
1686 void PF_changeyaw (void)
1687 {
1688         edict_t         *ent;
1689         float           ideal, current, move, speed;
1690
1691         ent = PROG_TO_EDICT(pr_global_struct->self);
1692         if (ent == sv.edicts)
1693                 PF_WARNING("changeyaw: can not modify world entity\n");
1694         if (ent->e->free)
1695                 PF_WARNING("changeyaw: can not modify free entity\n");
1696         current = ANGLEMOD(ent->v->angles[1]);
1697         ideal = ent->v->ideal_yaw;
1698         speed = ent->v->yaw_speed;
1699
1700         if (current == ideal)
1701                 return;
1702         move = ideal - current;
1703         if (ideal > current)
1704         {
1705                 if (move >= 180)
1706                         move = move - 360;
1707         }
1708         else
1709         {
1710                 if (move <= -180)
1711                         move = move + 360;
1712         }
1713         if (move > 0)
1714         {
1715                 if (move > speed)
1716                         move = speed;
1717         }
1718         else
1719         {
1720                 if (move < -speed)
1721                         move = -speed;
1722         }
1723
1724         ent->v->angles[1] = ANGLEMOD (current + move);
1725 }
1726
1727 /*
1728 ==============
1729 PF_changepitch
1730 ==============
1731 */
1732 void PF_changepitch (void)
1733 {
1734         edict_t         *ent;
1735         float           ideal, current, move, speed;
1736         eval_t          *val;
1737
1738         ent = G_EDICT(OFS_PARM0);
1739         if (ent == sv.edicts)
1740                 PF_WARNING("changepitch: can not modify world entity\n");
1741         if (ent->e->free)
1742                 PF_WARNING("changepitch: can not modify free entity\n");
1743         current = ANGLEMOD( ent->v->angles[0] );
1744         if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1745                 ideal = val->_float;
1746         else
1747         {
1748                 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1749                 return;
1750         }
1751         if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1752                 speed = val->_float;
1753         else
1754         {
1755                 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1756                 return;
1757         }
1758
1759         if (current == ideal)
1760                 return;
1761         move = ideal - current;
1762         if (ideal > current)
1763         {
1764                 if (move >= 180)
1765                         move = move - 360;
1766         }
1767         else
1768         {
1769                 if (move <= -180)
1770                         move = move + 360;
1771         }
1772         if (move > 0)
1773         {
1774                 if (move > speed)
1775                         move = speed;
1776         }
1777         else
1778         {
1779                 if (move < -speed)
1780                         move = -speed;
1781         }
1782
1783         ent->v->angles[0] = ANGLEMOD (current + move);
1784 }
1785
1786 /*
1787 ===============================================================================
1788
1789 MESSAGE WRITING
1790
1791 ===============================================================================
1792 */
1793
1794 #define MSG_BROADCAST   0               // unreliable to all
1795 #define MSG_ONE                 1               // reliable to one (msg_entity)
1796 #define MSG_ALL                 2               // reliable to all
1797 #define MSG_INIT                3               // write to the init string
1798
1799 sizebuf_t *WriteDest (void)
1800 {
1801         int             entnum;
1802         int             dest;
1803         edict_t *ent;
1804
1805         dest = G_FLOAT(OFS_PARM0);
1806         switch (dest)
1807         {
1808         case MSG_BROADCAST:
1809                 return &sv.datagram;
1810
1811         case MSG_ONE:
1812                 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1813                 entnum = NUM_FOR_EDICT(ent);
1814                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1815                         Host_Error("WriteDest: tried to write to non-client\n");
1816                 return &svs.clients[entnum-1].message;
1817
1818         case MSG_ALL:
1819                 return &sv.reliable_datagram;
1820
1821         case MSG_INIT:
1822                 return &sv.signon;
1823
1824         default:
1825                 Host_Error("WriteDest: bad destination");
1826                 break;
1827         }
1828
1829         return NULL;
1830 }
1831
1832 void PF_WriteByte (void)
1833 {
1834         MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1835 }
1836
1837 void PF_WriteChar (void)
1838 {
1839         MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1840 }
1841
1842 void PF_WriteShort (void)
1843 {
1844         MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1845 }
1846
1847 void PF_WriteLong (void)
1848 {
1849         MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1850 }
1851
1852 void PF_WriteAngle (void)
1853 {
1854         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1855 }
1856
1857 void PF_WriteCoord (void)
1858 {
1859         MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1860 }
1861
1862 void PF_WriteString (void)
1863 {
1864         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1865 }
1866
1867
1868 void PF_WriteEntity (void)
1869 {
1870         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1871 }
1872
1873 //=============================================================================
1874
1875 void PF_makestatic (void)
1876 {
1877         edict_t *ent;
1878         int i, large;
1879
1880         ent = G_EDICT(OFS_PARM0);
1881         if (ent == sv.edicts)
1882                 PF_WARNING("makestatic: can not modify world entity\n");
1883         if (ent->e->free)
1884                 PF_WARNING("makestatic: can not modify free entity\n");
1885
1886         large = false;
1887         if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1888                 large = true;
1889
1890         if (large)
1891         {
1892                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1893                 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1894                 MSG_WriteShort (&sv.signon, ent->v->frame);
1895         }
1896         else
1897         {
1898                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1899                 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1900                 MSG_WriteByte (&sv.signon, ent->v->frame);
1901         }
1902
1903         MSG_WriteByte (&sv.signon, ent->v->colormap);
1904         MSG_WriteByte (&sv.signon, ent->v->skin);
1905         for (i=0 ; i<3 ; i++)
1906         {
1907                 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1908                 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1909         }
1910
1911 // throw the entity away now
1912         ED_Free (ent);
1913 }
1914
1915 //=============================================================================
1916
1917 /*
1918 ==============
1919 PF_setspawnparms
1920 ==============
1921 */
1922 void PF_setspawnparms (void)
1923 {
1924         edict_t *ent;
1925         int             i;
1926         client_t        *client;
1927
1928         ent = G_EDICT(OFS_PARM0);
1929         i = NUM_FOR_EDICT(ent);
1930         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1931         {
1932                 Con_Print("tried to setspawnparms on a non-client\n");
1933                 return;
1934         }
1935
1936         // copy spawn parms out of the client_t
1937         client = svs.clients + i-1;
1938         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1939                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1940 }
1941
1942 /*
1943 ==============
1944 PF_changelevel
1945 ==============
1946 */
1947 void PF_changelevel (void)
1948 {
1949         char    *s;
1950
1951 // make sure we don't issue two changelevels
1952         if (svs.changelevel_issued)
1953                 return;
1954         svs.changelevel_issued = true;
1955
1956         s = G_STRING(OFS_PARM0);
1957         Cbuf_AddText (va("changelevel %s\n",s));
1958 }
1959
1960 void PF_sin (void)
1961 {
1962         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1963 }
1964
1965 void PF_cos (void)
1966 {
1967         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1968 }
1969
1970 void PF_sqrt (void)
1971 {
1972         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1973 }
1974
1975 /*
1976 =================
1977 PF_RandomVec
1978
1979 Returns a vector of length < 1
1980
1981 randomvec()
1982 =================
1983 */
1984 void PF_randomvec (void)
1985 {
1986         vec3_t          temp;
1987         do
1988         {
1989                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1990                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1991                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1992         }
1993         while (DotProduct(temp, temp) >= 1);
1994         VectorCopy (temp, G_VECTOR(OFS_RETURN));
1995 }
1996
1997 /*
1998 =================
1999 PF_GetLight
2000
2001 Returns a color vector indicating the lighting at the requested point.
2002
2003 (Internal Operation note: actually measures the light beneath the point, just like
2004                           the model lighting on the client)
2005
2006 getlight(vector)
2007 =================
2008 */
2009 void PF_GetLight (void)
2010 {
2011         vec3_t ambientcolor, diffusecolor, diffusenormal;
2012         vec_t *p;
2013         p = G_VECTOR(OFS_PARM0);
2014         VectorClear(ambientcolor);
2015         VectorClear(diffusecolor);
2016         VectorClear(diffusenormal);
2017         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2018                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2019         VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2020 }
2021
2022 void PF_registercvar (void)
2023 {
2024         char *name, *value;
2025         name = G_STRING(OFS_PARM0);
2026         value = G_STRING(OFS_PARM1);
2027         G_FLOAT(OFS_RETURN) = 0;
2028
2029 // first check to see if it has already been defined
2030         if (Cvar_FindVar (name))
2031                 return;
2032
2033 // check for overlap with a command
2034         if (Cmd_Exists (name))
2035         {
2036                 Con_Printf("PF_registercvar: %s is a command\n", name);
2037                 return;
2038         }
2039
2040         Cvar_Get(name, value, 0);
2041
2042         G_FLOAT(OFS_RETURN) = 1; // success
2043 }
2044
2045 /*
2046 =================
2047 PF_min
2048
2049 returns the minimum of two supplied floats
2050
2051 min(a, b)
2052 =================
2053 */
2054 void PF_min (void)
2055 {
2056         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2057         if (pr_argc == 2)
2058                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2059         else if (pr_argc >= 3)
2060         {
2061                 int i;
2062                 float f = G_FLOAT(OFS_PARM0);
2063                 for (i = 1;i < pr_argc;i++)
2064                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
2065                                 f = G_FLOAT((OFS_PARM0+i*3));
2066                 G_FLOAT(OFS_RETURN) = f;
2067         }
2068         else
2069         {
2070                 G_FLOAT(OFS_RETURN) = 0;
2071                 PF_WARNING("min: must supply at least 2 floats\n");
2072         }
2073 }
2074
2075 /*
2076 =================
2077 PF_max
2078
2079 returns the maximum of two supplied floats
2080
2081 max(a, b)
2082 =================
2083 */
2084 void PF_max (void)
2085 {
2086         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2087         if (pr_argc == 2)
2088                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2089         else if (pr_argc >= 3)
2090         {
2091                 int i;
2092                 float f = G_FLOAT(OFS_PARM0);
2093                 for (i = 1;i < pr_argc;i++)
2094                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
2095                                 f = G_FLOAT((OFS_PARM0+i*3));
2096                 G_FLOAT(OFS_RETURN) = f;
2097         }
2098         else
2099         {
2100                 G_FLOAT(OFS_RETURN) = 0;
2101                 PF_WARNING("max: must supply at least 2 floats\n");
2102         }
2103 }
2104
2105 /*
2106 =================
2107 PF_bound
2108
2109 returns number bounded by supplied range
2110
2111 min(min, value, max)
2112 =================
2113 */
2114 void PF_bound (void)
2115 {
2116         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2117 }
2118
2119 /*
2120 =================
2121 PF_pow
2122
2123 returns a raised to power b
2124
2125 pow(a, b)
2126 =================
2127 */
2128 void PF_pow (void)
2129 {
2130         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2131 }
2132
2133 /*
2134 =================
2135 PF_copyentity
2136
2137 copies data from one entity to another
2138
2139 copyentity(src, dst)
2140 =================
2141 */
2142 void PF_copyentity (void)
2143 {
2144         edict_t *in, *out;
2145         in = G_EDICT(OFS_PARM0);
2146         if (in == sv.edicts)
2147                 PF_WARNING("copyentity: can not read world entity\n");
2148         if (in->e->free)
2149                 PF_WARNING("copyentity: can not read free entity\n");
2150         out = G_EDICT(OFS_PARM1);
2151         if (out == sv.edicts)
2152                 PF_WARNING("copyentity: can not modify world entity\n");
2153         if (out->e->free)
2154                 PF_WARNING("copyentity: can not modify free entity\n");
2155         memcpy(out->v, in->v, progs->entityfields * 4);
2156 }
2157
2158 /*
2159 =================
2160 PF_setcolor
2161
2162 sets the color of a client and broadcasts the update to all connected clients
2163
2164 setcolor(clientent, value)
2165 =================
2166 */
2167 void PF_setcolor (void)
2168 {
2169         client_t *client;
2170         int entnum, i;
2171         eval_t *val;
2172
2173         entnum = G_EDICTNUM(OFS_PARM0);
2174         i = G_FLOAT(OFS_PARM1);
2175
2176         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2177         {
2178                 Con_Print("tried to setcolor a non-client\n");
2179                 return;
2180         }
2181
2182         client = svs.clients + entnum-1;
2183         if (client->edict)
2184         {
2185                 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2186                         val->_float = i;
2187                 client->edict->v->team = (i & 15) + 1;
2188         }
2189         client->colors = i;
2190         if (client->old_colors != client->colors)
2191         {
2192                 client->old_colors = client->colors;
2193                 // send notification to all clients
2194                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2195                 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2196                 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2197         }
2198 }
2199
2200 /*
2201 =================
2202 PF_effect
2203
2204 effect(origin, modelname, startframe, framecount, framerate)
2205 =================
2206 */
2207 void PF_effect (void)
2208 {
2209         int i;
2210         char *s;
2211         s = G_STRING(OFS_PARM1);
2212         if (!s || !s[0])
2213                 PF_WARNING("effect: no model specified\n");
2214
2215         i = SV_ModelIndex(s, 1);
2216         if (!i)
2217                 PF_WARNING("effect: model not precached\n");
2218         SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2219 }
2220
2221 void PF_te_blood (void)
2222 {
2223         if (G_FLOAT(OFS_PARM2) < 1)
2224                 return;
2225         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2226         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2227         // origin
2228         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2229         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2230         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2231         // velocity
2232         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2233         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2234         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2235         // count
2236         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2237 }
2238
2239 void PF_te_bloodshower (void)
2240 {
2241         if (G_FLOAT(OFS_PARM3) < 1)
2242                 return;
2243         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2244         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2245         // min
2246         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2247         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2248         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2249         // max
2250         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2251         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2252         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2253         // speed
2254         MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2255         // count
2256         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2257 }
2258
2259 void PF_te_explosionrgb (void)
2260 {
2261         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2262         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2263         // origin
2264         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2265         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2266         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2267         // color
2268         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2269         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2270         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2271 }
2272
2273 void PF_te_particlecube (void)
2274 {
2275         if (G_FLOAT(OFS_PARM3) < 1)
2276                 return;
2277         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2279         // min
2280         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2281         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2282         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2283         // max
2284         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2285         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2286         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2287         // velocity
2288         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2289         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2290         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2291         // count
2292         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2293         // color
2294         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2295         // gravity true/false
2296         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2297         // randomvel
2298         MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2299 }
2300
2301 void PF_te_particlerain (void)
2302 {
2303         if (G_FLOAT(OFS_PARM3) < 1)
2304                 return;
2305         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2306         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2307         // min
2308         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2309         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2310         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2311         // max
2312         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2313         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2314         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2315         // velocity
2316         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2317         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2318         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2319         // count
2320         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2321         // color
2322         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2323 }
2324
2325 void PF_te_particlesnow (void)
2326 {
2327         if (G_FLOAT(OFS_PARM3) < 1)
2328                 return;
2329         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2330         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2331         // min
2332         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2333         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2334         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2335         // max
2336         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2337         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2338         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2339         // velocity
2340         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2341         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2342         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2343         // count
2344         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2345         // color
2346         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2347 }
2348
2349 void PF_te_spark (void)
2350 {
2351         if (G_FLOAT(OFS_PARM2) < 1)
2352                 return;
2353         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2354         MSG_WriteByte(&sv.datagram, TE_SPARK);
2355         // origin
2356         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2357         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2358         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2359         // velocity
2360         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2361         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2362         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2363         // count
2364         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2365 }
2366
2367 void PF_te_gunshotquad (void)
2368 {
2369         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2370         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
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_spikequad (void)
2378 {
2379         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2380         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
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_superspikequad (void)
2388 {
2389         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2390         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
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_explosionquad (void)
2398 {
2399         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2400         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
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_smallflash (void)
2408 {
2409         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2410         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2411         // origin
2412         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2413         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2414         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2415 }
2416
2417 void PF_te_customflash (void)
2418 {
2419         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2420                 return;
2421         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2423         // origin
2424         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2425         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2426         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2427         // radius
2428         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2429         // lifetime
2430         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2431         // color
2432         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2433         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2434         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2435 }
2436
2437 void PF_te_gunshot (void)
2438 {
2439         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2440         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
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_spike (void)
2448 {
2449         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2450         MSG_WriteByte(&sv.datagram, TE_SPIKE);
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_superspike (void)
2458 {
2459         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
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_explosion (void)
2468 {
2469         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2470         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
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_tarexplosion (void)
2478 {
2479         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2480         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
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_wizspike (void)
2488 {
2489         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2490         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
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_knightspike (void)
2498 {
2499         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2500         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
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_lavasplash (void)
2508 {
2509         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2510         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
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_teleport (void)
2518 {
2519         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2520         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
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 }
2526
2527 void PF_te_explosion2 (void)
2528 {
2529         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2530         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2531         // origin
2532         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2533         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2534         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2535         // color
2536         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2537         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2538 }
2539
2540 void PF_te_lightning1 (void)
2541 {
2542         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2543         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2544         // owner entity
2545         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2546         // start
2547         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2548         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2549         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2550         // end
2551         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2552         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2553         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2554 }
2555
2556 void PF_te_lightning2 (void)
2557 {
2558         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2559         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2560         // owner entity
2561         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2562         // start
2563         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2564         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2565         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2566         // end
2567         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2568         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2569         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2570 }
2571
2572 void PF_te_lightning3 (void)
2573 {
2574         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2575         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2576         // owner entity
2577         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2578         // start
2579         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2580         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2581         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2582         // end
2583         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2584         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2585         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2586 }
2587
2588 void PF_te_beam (void)
2589 {
2590         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2591         MSG_WriteByte(&sv.datagram, TE_BEAM);
2592         // owner entity
2593         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2594         // start
2595         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2596         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2597         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2598         // end
2599         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2600         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2601         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2602 }
2603
2604 void PF_te_plasmaburn (void)
2605 {
2606         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2607         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2608         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2609         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2610         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2611 }
2612
2613 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
2614 {
2615         int i, j, k;
2616         float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2617         const int *e;
2618         bestdist = 1000000000;
2619         VectorCopy(p, out);
2620         for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2621         {
2622                 // clip original point to each triangle of the surface and find the
2623                 // triangle that is closest
2624                 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
2625                 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
2626                 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
2627                 TriangleNormal(v[0], v[1], v[2], facenormal);
2628                 VectorNormalize(facenormal);
2629                 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2630                 VectorMA(p, offsetdist, facenormal, temp);
2631                 for (j = 0, k = 2;j < 3;k = j, j++)
2632                 {
2633                         VectorSubtract(v[k], v[j], edgenormal);
2634                         CrossProduct(edgenormal, facenormal, sidenormal);
2635                         VectorNormalize(sidenormal);
2636                         offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2637                         if (offsetdist < 0)
2638                                 VectorMA(temp, offsetdist, sidenormal, temp);
2639                 }
2640                 dist = VectorDistance2(temp, p);
2641                 if (bestdist > dist)
2642                 {
2643                         bestdist = dist;
2644                         VectorCopy(temp, out);
2645                 }
2646         }
2647 }
2648
2649 static msurface_t *getsurface(edict_t *ed, int surfacenum)
2650 {
2651         int modelindex;
2652         model_t *model;
2653         if (!ed || ed->e->free)
2654                 return NULL;
2655         modelindex = ed->v->modelindex;
2656         if (modelindex < 1 || modelindex >= MAX_MODELS)
2657                 return NULL;
2658         model = sv.models[modelindex];
2659         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2660                 return NULL;
2661         return model->data_surfaces + surfacenum + model->firstmodelsurface;
2662 }
2663
2664
2665 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2666 void PF_getsurfacenumpoints(void)
2667 {
2668         msurface_t *surface;
2669         // return 0 if no such surface
2670         if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2671         {
2672                 G_FLOAT(OFS_RETURN) = 0;
2673                 return;
2674         }
2675
2676         // note: this (incorrectly) assumes it is a simple polygon
2677         G_FLOAT(OFS_RETURN) = surface->num_vertices;
2678 }
2679 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2680 void PF_getsurfacepoint(void)
2681 {
2682         edict_t *ed;
2683         msurface_t *surface;
2684         int pointnum;
2685         VectorClear(G_VECTOR(OFS_RETURN));
2686         ed = G_EDICT(OFS_PARM0);
2687         if (!ed || ed->e->free)
2688                 return;
2689         if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2690                 return;
2691         // note: this (incorrectly) assumes it is a simple polygon
2692         pointnum = G_FLOAT(OFS_PARM2);
2693         if (pointnum < 0 || pointnum >= surface->num_vertices)
2694                 return;
2695         // FIXME: implement rotation/scaling
2696         VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2697 }
2698 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2699 void PF_getsurfacenormal(void)
2700 {
2701         msurface_t *surface;
2702         vec3_t normal;
2703         VectorClear(G_VECTOR(OFS_RETURN));
2704         if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2705                 return;
2706         // FIXME: implement rotation/scaling
2707         // note: this (incorrectly) assumes it is a simple polygon
2708         // note: this only returns the first triangle, so it doesn't work very
2709         // well for curved surfaces or arbitrary meshes
2710         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);
2711         VectorNormalize(normal);
2712         VectorCopy(normal, G_VECTOR(OFS_RETURN));
2713 }
2714 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2715 void PF_getsurfacetexture(void)
2716 {
2717         msurface_t *surface;
2718         G_INT(OFS_RETURN) = 0;
2719         if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2720                 return;
2721         G_INT(OFS_RETURN) = PR_SetString(surface->texture->name);
2722 }
2723 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2724 void PF_getsurfacenearpoint(void)
2725 {
2726         int surfacenum, best, modelindex;
2727         vec3_t clipped, p;
2728         vec_t dist, bestdist;
2729         edict_t *ed;
2730         model_t *model;
2731         msurface_t *surface;
2732         vec_t *point;
2733         G_FLOAT(OFS_RETURN) = -1;
2734         ed = G_EDICT(OFS_PARM0);
2735         point = G_VECTOR(OFS_PARM1);
2736
2737         if (!ed || ed->e->free)
2738                 return;
2739         modelindex = ed->v->modelindex;
2740         if (modelindex < 1 || modelindex >= MAX_MODELS)
2741                 return;
2742         model = sv.models[modelindex];
2743         if (!model->num_surfaces)
2744                 return;
2745
2746         // FIXME: implement rotation/scaling
2747         VectorSubtract(point, ed->v->origin, p);
2748         best = -1;
2749         bestdist = 1000000000;
2750         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2751         {
2752                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2753                 // first see if the nearest point on the surface's box is closer than the previous match
2754                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2755                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2756                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2757                 dist = VectorLength2(clipped);
2758                 if (dist < bestdist)
2759                 {
2760                         // it is, check the nearest point on the actual geometry
2761                         clippointtosurface(surface, p, clipped);
2762                         VectorSubtract(clipped, p, clipped);
2763                         dist += VectorLength2(clipped);
2764                         if (dist < bestdist)
2765                         {
2766                                 // that's closer too, store it as the best match
2767                                 best = surfacenum;
2768                                 bestdist = dist;
2769                         }
2770                 }
2771         }
2772         G_FLOAT(OFS_RETURN) = best;
2773 }
2774 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2775 void PF_getsurfaceclippedpoint(void)
2776 {
2777         edict_t *ed;
2778         msurface_t *surface;
2779         vec3_t p, out;
2780         VectorClear(G_VECTOR(OFS_RETURN));
2781         ed = G_EDICT(OFS_PARM0);
2782         if (!ed || ed->e->free)
2783                 return;
2784         if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2785                 return;
2786         // FIXME: implement rotation/scaling
2787         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2788         clippointtosurface(surface, p, out);
2789         // FIXME: implement rotation/scaling
2790         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2791 }
2792
2793 #define MAX_PRFILES 256
2794
2795 qfile_t *pr_files[MAX_PRFILES];
2796
2797 void PR_Files_Init(void)
2798 {
2799         memset(pr_files, 0, sizeof(pr_files));
2800 }
2801
2802 void PR_Files_CloseAll(void)
2803 {
2804         int i;
2805         for (i = 0;i < MAX_PRFILES;i++)
2806         {
2807                 if (pr_files[i])
2808                         FS_Close(pr_files[i]);
2809                 pr_files[i] = NULL;
2810         }
2811 }
2812
2813 //float(string s) stof = #81; // get numerical value from a string
2814 void PF_stof(void)
2815 {
2816         char string[STRINGTEMP_LENGTH];
2817         PF_VarString(0, string, sizeof(string));
2818         G_FLOAT(OFS_RETURN) = atof(string);
2819 }
2820
2821 //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
2822 void PF_fopen(void)
2823 {
2824         int filenum, mode;
2825         char *modestring, *filename;
2826         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2827                 if (pr_files[filenum] == NULL)
2828                         break;
2829         if (filenum >= MAX_PRFILES)
2830         {
2831                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2832                 G_FLOAT(OFS_RETURN) = -2;
2833                 return;
2834         }
2835         mode = G_FLOAT(OFS_PARM1);
2836         switch(mode)
2837         {
2838         case 0: // FILE_READ
2839                 modestring = "rb";
2840                 break;
2841         case 1: // FILE_APPEND
2842                 modestring = "ab";
2843                 break;
2844         case 2: // FILE_WRITE
2845                 modestring = "wb";
2846                 break;
2847         default:
2848                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2849                 G_FLOAT(OFS_RETURN) = -3;
2850                 return;
2851         }
2852         filename = G_STRING(OFS_PARM0);
2853         // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2854         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false, false);
2855
2856         if (pr_files[filenum] == NULL && modestring == "rb")
2857                 pr_files[filenum] = FS_Open(filename, modestring, false, false);
2858
2859         if (pr_files[filenum] == NULL)
2860                 G_FLOAT(OFS_RETURN) = -1;
2861         else
2862                 G_FLOAT(OFS_RETURN) = filenum;
2863 }
2864
2865 //void(float fhandle) fclose = #111; // closes a file
2866 void PF_fclose(void)
2867 {
2868         int filenum = G_FLOAT(OFS_PARM0);
2869         if (filenum < 0 || filenum >= MAX_PRFILES)
2870         {
2871                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2872                 return;
2873         }
2874         if (pr_files[filenum] == NULL)
2875         {
2876                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2877                 return;
2878         }
2879         FS_Close(pr_files[filenum]);
2880         pr_files[filenum] = NULL;
2881 }
2882
2883 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2884 void PF_fgets(void)
2885 {
2886         int c, end;
2887         static char string[STRINGTEMP_LENGTH];
2888         int filenum = G_FLOAT(OFS_PARM0);
2889         if (filenum < 0 || filenum >= MAX_PRFILES)
2890         {
2891                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2892                 return;
2893         }
2894         if (pr_files[filenum] == NULL)
2895         {
2896                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2897                 return;
2898         }
2899         end = 0;
2900         for (;;)
2901         {
2902                 c = FS_Getc(pr_files[filenum]);
2903                 if (c == '\r' || c == '\n' || c < 0)
2904                         break;
2905                 if (end < STRINGTEMP_LENGTH - 1)
2906                         string[end++] = c;
2907         }
2908         string[end] = 0;
2909         // remove \n following \r
2910         if (c == '\r')
2911         {
2912                 c = FS_Getc(pr_files[filenum]);
2913                 if (c != '\n')
2914                         FS_UnGetc(pr_files[filenum], (unsigned char)c);
2915         }
2916         if (developer.integer)
2917                 Con_Printf("fgets: %s\n", string);
2918         if (c >= 0 || end)
2919                 G_INT(OFS_RETURN) = PR_SetString(string);
2920         else
2921                 G_INT(OFS_RETURN) = 0;
2922 }
2923
2924 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2925 void PF_fputs(void)
2926 {
2927         int stringlength;
2928         char string[STRINGTEMP_LENGTH];
2929         int filenum = G_FLOAT(OFS_PARM0);
2930         if (filenum < 0 || filenum >= MAX_PRFILES)
2931         {
2932                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2933                 return;
2934         }
2935         if (pr_files[filenum] == NULL)
2936         {
2937                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2938                 return;
2939         }
2940         PF_VarString(1, string, sizeof(string));
2941         if ((stringlength = strlen(string)))
2942                 FS_Write(pr_files[filenum], string, stringlength);
2943         if (developer.integer)
2944                 Con_Printf("fputs: %s\n", string);
2945 }
2946
2947 //float(string s) strlen = #114; // returns how many characters are in a string
2948 void PF_strlen(void)
2949 {
2950         char *s;
2951         s = G_STRING(OFS_PARM0);
2952         if (s)
2953                 G_FLOAT(OFS_RETURN) = strlen(s);
2954         else
2955                 G_FLOAT(OFS_RETURN) = 0;
2956 }
2957
2958 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2959 void PF_strcat(void)
2960 {
2961         char *s = PR_GetTempString();
2962         PF_VarString(0, s, STRINGTEMP_LENGTH);
2963         G_INT(OFS_RETURN) = PR_SetString(s);
2964 }
2965
2966 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2967 void PF_substring(void)
2968 {
2969         int i, start, length;
2970         char *s, *string = PR_GetTempString();
2971         s = G_STRING(OFS_PARM0);
2972         start = G_FLOAT(OFS_PARM1);
2973         length = G_FLOAT(OFS_PARM2);
2974         if (!s)
2975                 s = "";
2976         for (i = 0;i < start && *s;i++, s++);
2977         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2978                 string[i] = *s;
2979         string[i] = 0;
2980         G_INT(OFS_RETURN) = PR_SetString(string);
2981 }
2982
2983 //vector(string s) stov = #117; // returns vector value from a string
2984 void PF_stov(void)
2985 {
2986         char string[STRINGTEMP_LENGTH];
2987         PF_VarString(0, string, sizeof(string));
2988         Math_atov(string, G_VECTOR(OFS_RETURN));
2989 }
2990
2991 //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)
2992 void PF_strzone(void)
2993 {
2994         char *in, *out;
2995         in = G_STRING(OFS_PARM0);
2996         out = PR_Alloc(strlen(in) + 1);
2997         strcpy(out, in);
2998         G_INT(OFS_RETURN) = PR_SetString(out);
2999 }
3000
3001 //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!!!)
3002 void PF_strunzone(void)
3003 {
3004         PR_Free(G_STRING(OFS_PARM0));
3005 }
3006
3007 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3008 //this function originally written by KrimZon, made shorter by LordHavoc
3009 void PF_clientcommand (void)
3010 {
3011         client_t *temp_client;
3012         int i;
3013
3014         //find client for this entity
3015         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3016         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3017         {
3018                 Con_Print("PF_clientcommand: entity is not a client\n");
3019                 return;
3020         }
3021
3022         temp_client = host_client;
3023         host_client = svs.clients + i;
3024         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3025         host_client = temp_client;
3026 }
3027
3028 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3029 //this function originally written by KrimZon, made shorter by LordHavoc
3030 //20040203: rewritten by LordHavoc (no longer uses allocations)
3031 int num_tokens = 0;
3032 char *tokens[256], tokenbuf[4096];
3033 void PF_tokenize (void)
3034 {
3035         int pos;
3036         const char *p;
3037         p = G_STRING(OFS_PARM0);
3038
3039         num_tokens = 0;
3040         pos = 0;
3041         while(COM_ParseToken(&p, false))
3042         {
3043                 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3044                         break;
3045                 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3046                         break;
3047                 tokens[num_tokens++] = tokenbuf + pos;
3048                 strcpy(tokenbuf + pos, com_token);
3049                 pos += strlen(com_token) + 1;
3050         }
3051
3052         G_FLOAT(OFS_RETURN) = num_tokens;
3053 }
3054
3055 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3056 //this function originally written by KrimZon, made shorter by LordHavoc
3057 void PF_argv (void)
3058 {
3059         int token_num = G_FLOAT(OFS_PARM0);
3060         if (token_num >= 0 && token_num < num_tokens)
3061                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3062         else
3063                 G_INT(OFS_RETURN) = PR_SetString("");
3064 }
3065
3066 //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)
3067 void PF_setattachment (void)
3068 {
3069         edict_t *e = G_EDICT(OFS_PARM0);
3070         edict_t *tagentity = G_EDICT(OFS_PARM1);
3071         char *tagname = G_STRING(OFS_PARM2);
3072         eval_t *v;
3073         int modelindex;
3074         model_t *model;
3075
3076         if (e == sv.edicts)
3077                 PF_WARNING("setattachment: can not modify world entity\n");
3078         if (e->e->free)
3079                 PF_WARNING("setattachment: can not modify free entity\n");
3080
3081         if (tagentity == NULL)
3082                 tagentity = sv.edicts;
3083
3084         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3085         if (v)
3086                 v->edict = EDICT_TO_PROG(tagentity);
3087
3088         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3089         if (v)
3090                 v->_float = 0;
3091         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3092         {
3093                 modelindex = (int)tagentity->v->modelindex;
3094                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3095                 {
3096                         v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->v->skin, tagname);
3097                         if (v->_float == 0)
3098                                 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);
3099                 }
3100                 else
3101                         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));
3102         }
3103 }
3104
3105 /////////////////////////////////////////
3106 // DP_MD3_TAGINFO extension coded by VorteX
3107
3108 int SV_GetTagIndex (edict_t *e, char *tagname)
3109 {
3110         int i;
3111         model_t *model;
3112
3113         i = e->v->modelindex;
3114         if (i < 1 || i >= MAX_MODELS)
3115                 return -1;
3116         model = sv.models[i];
3117
3118         return Mod_Alias_GetTagIndexForName(model, e->v->skin, tagname);
3119 };
3120
3121 // Warnings/errors code:
3122 // 0 - normal (everything all-right)
3123 // 1 - world entity
3124 // 2 - free entity
3125 // 3 - null or non-precached model
3126 // 4 - no tags with requested index
3127 // 5 - runaway loop at attachment chain
3128 extern cvar_t cl_bob;
3129 extern cvar_t cl_bobcycle;
3130 extern cvar_t cl_bobup;
3131 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3132 {
3133         eval_t *val;
3134         int modelindex, reqframe, attachloop;
3135         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3136         edict_t *attachent;
3137         model_t *model;
3138
3139         Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3140
3141         if (ent == sv.edicts)
3142                 return 1;
3143         if (ent->e->free)
3144                 return 2;
3145
3146         modelindex = (int)ent->v->modelindex;
3147         if (modelindex <= 0 || modelindex > MAX_MODELS)
3148                 return 3;
3149
3150         model = sv.models[modelindex];
3151
3152         if (ent->v->frame >= 0 && ent->v->frame < model->numframes && model->animscenes)
3153                 reqframe = model->animscenes[(int)ent->v->frame].firstframe;
3154         else
3155                 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3156
3157         // get initial tag matrix
3158         if (tagindex)
3159         {
3160                 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
3161                 if (ret)
3162                         return ret;
3163         }
3164         else
3165                 Matrix4x4_CreateIdentity(&tagmatrix);
3166
3167         if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3168         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3169                 attachloop = 0;
3170                 do
3171                 {
3172                         attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3173                         val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3174                         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)
3175                                 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->v->frame].firstframe, val->_float - 1, &attachmatrix);
3176                         else
3177                                 Matrix4x4_CreateIdentity(&attachmatrix);
3178
3179                         // apply transformation by child entity matrix
3180                         val = GETEDICTFIELDVALUE(ent, eval_scale);
3181                         if (val->_float == 0)
3182                                 val->_float = 1;
3183                         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);
3184                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3185                         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]);
3186                         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]);
3187                         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]);
3188                         Matrix4x4_Copy(&tagmatrix, out);
3189
3190                         // finally transformate by matrix of tag on parent entity
3191                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3192                         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];
3193                         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];
3194                         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];
3195                         Matrix4x4_Copy(&tagmatrix, out);
3196
3197                         ent = attachent;
3198                         attachloop += 1;
3199                         if (attachloop > 255) // prevent runaway looping
3200                                 return 5;
3201                 }
3202                 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3203         }
3204
3205         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3206         val = GETEDICTFIELDVALUE(ent, eval_scale);
3207         if (val->_float == 0)
3208                 val->_float = 1;
3209         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3210         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);
3211         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3212         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]);
3213         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]);
3214         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]);
3215
3216         if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3217         {// RENDER_VIEWMODEL magic
3218                 Matrix4x4_Copy(&tagmatrix, out);
3219                 ent = EDICT_NUM(val->edict);
3220
3221                 val = GETEDICTFIELDVALUE(ent, eval_scale);
3222                 if (val->_float == 0)
3223                         val->_float = 1;
3224
3225                 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);
3226                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3227                 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3228                 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3229                 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3230
3231                 /*
3232                 // Cl_bob, ported from rendering code
3233                 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3234                 {
3235                         double bob, cycle;
3236                         // LordHavoc: this code is *weird*, but not replacable (I think it
3237                         // should be done in QC on the server, but oh well, quake is quake)
3238                         // LordHavoc: figured out bobup: the time at which the sin is at 180
3239                         // degrees (which allows lengthening or squishing the peak or valley)
3240                         cycle = sv.time/cl_bobcycle.value;
3241                         cycle -= (int)cycle;
3242                         if (cycle < cl_bobup.value)
3243                                 cycle = sin(M_PI * cycle / cl_bobup.value);
3244                         else
3245                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3246                         // bob is proportional to velocity in the xy plane
3247                         // (don't count Z, or jumping messes it up)
3248                         bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3249                         bob = bob*0.3 + bob*0.7*cycle;
3250                         out->m[2][3] += bound(-7, bob, 4);
3251                 }
3252                 */
3253         }
3254         return 0;
3255 }
3256
3257 //float(entity ent, string tagname) gettagindex;
3258
3259 void PF_gettagindex (void)
3260 {
3261         edict_t *ent = G_EDICT(OFS_PARM0);
3262         char *tag_name = G_STRING(OFS_PARM1);
3263         int modelindex, tag_index;
3264
3265         if (ent == sv.edicts)
3266                 PF_WARNING("gettagindex: can't affect world entity\n");
3267         if (ent->e->free)
3268                 PF_WARNING("gettagindex: can't affect free entity\n");
3269
3270         modelindex = (int)ent->v->modelindex;
3271         tag_index = 0;
3272         if (modelindex <= 0 || modelindex > MAX_MODELS)
3273                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3274         else
3275         {
3276                 tag_index = SV_GetTagIndex(ent, tag_name);
3277                 if (tag_index == 0)
3278                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3279         }
3280         G_FLOAT(OFS_RETURN) = tag_index;
3281 };
3282
3283 //vector(entity ent, float tagindex) gettaginfo;
3284 void PF_gettaginfo (void)
3285 {
3286         edict_t *e = G_EDICT(OFS_PARM0);
3287         int tagindex = (int)G_FLOAT(OFS_PARM1);
3288         matrix4x4_t tag_matrix;
3289         int returncode;
3290
3291         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3292         Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3293
3294         switch(returncode)
3295         {
3296                 case 1:
3297                         PF_WARNING("gettagindex: can't affect world entity\n");
3298                         break;
3299                 case 2:
3300                         PF_WARNING("gettagindex: can't affect free entity\n");
3301                         break;
3302                 case 3:
3303                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3304                         break;
3305                 case 4:
3306                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3307                         break;
3308                 case 5:
3309                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3310                         break;
3311         }
3312 }
3313
3314
3315 /////////////////////////////////////////
3316 // DP_QC_FS_SEARCH extension
3317
3318 // qc fs search handling
3319 #define MAX_SEARCHES 128
3320
3321 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3322
3323 void PR_Search_Init(void)
3324 {
3325         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3326 }
3327
3328 void PR_Search_Reset(void)
3329 {
3330         int i;
3331         // reset the fssearch list
3332         for(i = 0; i < MAX_SEARCHES; i++)
3333                 if(pr_fssearchlist[i])
3334                         FS_FreeSearch(pr_fssearchlist[i]);
3335         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3336 }
3337
3338 /*
3339 =========
3340 PF_search_begin
3341
3342 float search_begin(string pattern, float caseinsensitive, float quiet)
3343 =========
3344 */
3345 void PF_search_begin(void)
3346 {
3347         int handle;
3348         char *pattern;
3349         int caseinsens, quiet;
3350
3351         pattern = G_STRING(OFS_PARM0);
3352
3353         PR_CheckEmptyString(pattern);
3354
3355         caseinsens = G_FLOAT(OFS_PARM1);
3356         quiet = G_FLOAT(OFS_PARM2);
3357
3358         for(handle = 0; handle < MAX_SEARCHES; handle++)
3359                 if(!pr_fssearchlist[handle])
3360                         break;
3361
3362         if(handle >= MAX_SEARCHES)
3363         {
3364                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3365                 G_FLOAT(OFS_RETURN) = -2;
3366                 return;
3367         }
3368
3369         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3370                 G_FLOAT(OFS_RETURN) = -1;
3371         else
3372                 G_FLOAT(OFS_RETURN) = handle;
3373 }
3374
3375 /*
3376 =========
3377 VM_search_end
3378
3379 void    search_end(float handle)
3380 =========
3381 */
3382 void PF_search_end(void)
3383 {
3384         int handle;
3385
3386         handle = G_FLOAT(OFS_PARM0);
3387
3388         if(handle < 0 || handle >= MAX_SEARCHES)
3389         {
3390                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3391                 return;
3392         }
3393         if(pr_fssearchlist[handle] == NULL)
3394         {
3395                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3396                 return;
3397         }
3398
3399         FS_FreeSearch(pr_fssearchlist[handle]);
3400         pr_fssearchlist[handle] = NULL;
3401 }
3402
3403 /*
3404 =========
3405 VM_search_getsize
3406
3407 float   search_getsize(float handle)
3408 =========
3409 */
3410 void PF_search_getsize(void)
3411 {
3412         int handle;
3413
3414         handle = G_FLOAT(OFS_PARM0);
3415
3416         if(handle < 0 || handle >= MAX_SEARCHES)
3417         {
3418                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3419                 return;
3420         }
3421         if(pr_fssearchlist[handle] == NULL)
3422         {
3423                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3424                 return;
3425         }
3426
3427         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3428 }
3429
3430 /*
3431 =========
3432 VM_search_getfilename
3433
3434 string  search_getfilename(float handle, float num)
3435 =========
3436 */
3437 void PF_search_getfilename(void)
3438 {
3439         int handle, filenum;
3440         char *tmp;
3441
3442         handle = G_FLOAT(OFS_PARM0);
3443         filenum = G_FLOAT(OFS_PARM1);
3444
3445         if(handle < 0 || handle >= MAX_SEARCHES)
3446         {
3447                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3448                 return;
3449         }
3450         if(pr_fssearchlist[handle] == NULL)
3451         {
3452                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3453                 return;
3454         }
3455         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3456         {
3457                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3458                 return;
3459         }
3460
3461         tmp = PR_GetTempString();
3462         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3463
3464         G_INT(OFS_RETURN) = PR_SetString(tmp);
3465 }
3466
3467 void PF_cvar_string (void)
3468 {
3469         char *str;
3470         cvar_t *var;
3471         char *tmp;
3472
3473         str = G_STRING(OFS_PARM0);
3474         var = Cvar_FindVar (str);
3475         if (var)
3476         {
3477                 tmp = PR_GetTempString();
3478                 strcpy(tmp, var->string);
3479         }
3480         else
3481                 tmp = "";
3482         G_INT(OFS_RETURN) = PR_SetString(tmp);
3483 }
3484
3485 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3486 void PF_dropclient (void)
3487 {
3488         int clientnum;
3489         client_t *oldhostclient;
3490         clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3491         if (clientnum < 0 || clientnum >= svs.maxclients)
3492                 PF_WARNING("dropclient: not a client\n");
3493         if (!svs.clients[clientnum].active)
3494                 PF_WARNING("dropclient: that client slot is not connected\n");
3495         oldhostclient = host_client;
3496         host_client = svs.clients + clientnum;
3497         SV_DropClient(false);
3498         host_client = oldhostclient;
3499 }
3500
3501 //entity() spawnclient (DP_SV_BOTCLIENT)
3502 void PF_spawnclient (void)
3503 {
3504         int i;
3505         edict_t *ed;
3506         pr_xfunction->builtinsprofile += 2;
3507         ed = sv.edicts;
3508         for (i = 0;i < svs.maxclients;i++)
3509         {
3510                 if (!svs.clients[i].active)
3511                 {
3512                         pr_xfunction->builtinsprofile += 100;
3513                         SV_ConnectClient (i, NULL);
3514                         ed = EDICT_NUM(i + 1);
3515                         break;
3516                 }
3517         }
3518         RETURN_EDICT(ed);
3519 }
3520
3521 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3522 void PF_clienttype (void)
3523 {
3524         int clientnum;
3525         clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3526         if (clientnum < 0 || clientnum >= svs.maxclients)
3527                 G_FLOAT(OFS_RETURN) = 3;
3528         else if (!svs.clients[clientnum].active)
3529                 G_FLOAT(OFS_RETURN) = 0;
3530         else if (svs.clients[clientnum].netconnection)
3531                 G_FLOAT(OFS_RETURN) = 1;
3532         else
3533                 G_FLOAT(OFS_RETURN) = 2;
3534 }
3535
3536 builtin_t pr_builtin[] =
3537 {
3538 NULL,                                           // #0
3539 PF_makevectors,                         // #1 void(entity e) makevectors
3540 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3541 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3542 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3543 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3544 PF_break,                                       // #6 void() break
3545 PF_random,                                      // #7 float() random
3546 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3547 PF_normalize,                           // #9 vector(vector v) normalize
3548 PF_error,                                       // #10 void(string e) error
3549 PF_objerror,                            // #11 void(string e) objerror
3550 PF_vlen,                                        // #12 float(vector v) vlen
3551 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3552 PF_Spawn,                                       // #14 entity() spawn
3553 PF_Remove,                                      // #15 void(entity e) remove
3554 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3555 PF_checkclient,                         // #17 entity() clientlist
3556 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3557 PF_precache_sound,                      // #19 void(string s) precache_sound
3558 PF_precache_model,                      // #20 void(string s) precache_model
3559 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3560 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3561 PF_bprint,                                      // #23 void(string s) bprint
3562 PF_sprint,                                      // #24 void(entity client, string s) sprint
3563 PF_dprint,                                      // #25 void(string s) dprint
3564 PF_ftos,                                        // #26 void(string s) ftos
3565 PF_vtos,                                        // #27 void(string s) vtos
3566 PF_coredump,                            // #28 void() coredump
3567 PF_traceon,                                     // #29 void() traceon
3568 PF_traceoff,                            // #30 void() traceoff
3569 PF_eprint,                                      // #31 void(entity e) eprint
3570 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3571 NULL,                                           // #33
3572 PF_droptofloor,                         // #34 float() droptofloor
3573 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3574 PF_rint,                                        // #36 float(float v) rint
3575 PF_floor,                                       // #37 float(float v) floor
3576 PF_ceil,                                        // #38 float(float v) ceil
3577 NULL,                                           // #39
3578 PF_checkbottom,                         // #40 float(entity e) checkbottom
3579 PF_pointcontents,                       // #41 float(vector v) pointcontents
3580 NULL,                                           // #42
3581 PF_fabs,                                        // #43 float(float f) fabs
3582 PF_aim,                                         // #44 vector(entity e, float speed) aim
3583 PF_cvar,                                        // #45 float(string s) cvar
3584 PF_localcmd,                            // #46 void(string s) localcmd
3585 PF_nextent,                                     // #47 entity(entity e) nextent
3586 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3587 PF_changeyaw,                           // #49 void() ChangeYaw
3588 NULL,                                           // #50
3589 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3590 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3591 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3592 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3593 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3594 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3595 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3596 PF_WriteString,                         // #58 void(float to, string s) WriteString
3597 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3598 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3599 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3600 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3601 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3602 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3603 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3604 NULL,                                           // #66
3605 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3606 PF_precache_file,                       // #68 string(string s) precache_file
3607 PF_makestatic,                          // #69 void(entity e) makestatic
3608 PF_changelevel,                         // #70 void(string s) changelevel
3609 NULL,                                           // #71
3610 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3611 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3612 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3613 PF_precache_model,                      // #75 string(string s) precache_model2
3614 PF_precache_sound,                      // #76 string(string s) precache_sound2
3615 PF_precache_file,                       // #77 string(string s) precache_file2
3616 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3617 NULL,                                           // #79
3618 NULL,                                           // #80
3619 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3620 NULL,                                           // #82
3621 NULL,                                           // #83
3622 NULL,                                           // #84
3623 NULL,                                           // #85
3624 NULL,                                           // #86
3625 NULL,                                           // #87
3626 NULL,                                           // #88
3627 NULL,                                           // #89
3628 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3629 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3630 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3631 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3632 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3633 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3634 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3635 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3636 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3637 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3638 NULL,                                           // #100
3639 NULL,                                           // #101
3640 NULL,                                           // #102
3641 NULL,                                           // #103
3642 NULL,                                           // #104
3643 NULL,                                           // #105
3644 NULL,                                           // #106
3645 NULL,                                           // #107
3646 NULL,                                           // #108
3647 NULL,                                           // #109
3648 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3649 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3650 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3651 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3652 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3653 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3654 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3655 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3656 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3657 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3658 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3659 a a a a a a a a                         // #120-199
3660 a a a a a a a a a a                     // #200-299
3661 a a a a a a a a a a                     // #300-399
3662 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3663 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3664 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3665 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3666 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3667 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3668 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3669 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3670 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3671 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3672 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3673 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3674 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3675 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3676 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3677 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3678 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3679 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3680 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3681 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3682 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3683 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3684 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3685 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3686 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3687 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3688 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3689 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3690 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3691 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3692 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3693 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3694 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3695 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3696 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3697 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3698 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3699 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3700 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3701 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3702 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3703 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3704 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3705 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3706 PF_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3707 PF_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
3708 PF_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3709 PF_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3710 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3711 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3712 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3713 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3714 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3715 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3716 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3717 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3718 NULL,                                           // #456
3719 NULL,                                           // #457
3720 NULL,                                           // #458
3721 NULL,                                           // #459
3722 a a a a                                         // #460-499 (LordHavoc)
3723 };
3724
3725 builtin_t *pr_builtins = pr_builtin;
3726 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3727
3728 void PR_Cmd_Init(void)
3729 {
3730         PR_Files_Init();
3731         PR_Search_Init();
3732 }
3733
3734 void PR_Cmd_Shutdown(void)
3735 {
3736 }
3737
3738 void PR_Cmd_Reset(void)
3739 {
3740         PR_Search_Reset();
3741         PR_Files_CloseAll();
3742 }
3743