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