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