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