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