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