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