]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - pr_cmds.c
8bdb8f0f5e3407723d333b1be9c2444b6790f3b7
[xonotic/darkplaces.git] / pr_cmds.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
25
26 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 "NXQ_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         MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1878 }
1879
1880 void PF_WriteCoord (void)
1881 {
1882         MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1883 }
1884
1885 void PF_WriteString (void)
1886 {
1887         MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1888 }
1889
1890
1891 void PF_WriteEntity (void)
1892 {
1893         MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1894 }
1895
1896 //=============================================================================
1897
1898 void PF_makestatic (void)
1899 {
1900         edict_t *ent;
1901         int i, large;
1902
1903         ent = G_EDICT(OFS_PARM0);
1904         if (ent == sv.edicts)
1905                 PF_WARNING("makestatic: can not modify world entity\n");
1906         if (ent->e->free)
1907                 PF_WARNING("makestatic: can not modify free entity\n");
1908
1909         large = false;
1910         if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1911                 large = true;
1912
1913         if (large)
1914         {
1915                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1916                 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1917                 MSG_WriteShort (&sv.signon, ent->v->frame);
1918         }
1919         else
1920         {
1921                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1922                 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1923                 MSG_WriteByte (&sv.signon, ent->v->frame);
1924         }
1925
1926         MSG_WriteByte (&sv.signon, ent->v->colormap);
1927         MSG_WriteByte (&sv.signon, ent->v->skin);
1928         for (i=0 ; i<3 ; i++)
1929         {
1930                 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1931                 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1932         }
1933
1934 // throw the entity away now
1935         ED_Free (ent);
1936 }
1937
1938 //=============================================================================
1939
1940 /*
1941 ==============
1942 PF_setspawnparms
1943 ==============
1944 */
1945 void PF_setspawnparms (void)
1946 {
1947         edict_t *ent;
1948         int             i;
1949         client_t        *client;
1950
1951         ent = G_EDICT(OFS_PARM0);
1952         i = NUM_FOR_EDICT(ent);
1953         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1954         {
1955                 Con_Print("tried to setspawnparms on a non-client\n");
1956                 return;
1957         }
1958
1959         // copy spawn parms out of the client_t
1960         client = svs.clients + i-1;
1961         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1962                 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1963 }
1964
1965 /*
1966 ==============
1967 PF_changelevel
1968 ==============
1969 */
1970 void PF_changelevel (void)
1971 {
1972         char    *s;
1973
1974 // make sure we don't issue two changelevels
1975         if (svs.changelevel_issued)
1976                 return;
1977         svs.changelevel_issued = true;
1978
1979         s = G_STRING(OFS_PARM0);
1980         Cbuf_AddText (va("changelevel %s\n",s));
1981 }
1982
1983 void PF_sin (void)
1984 {
1985         G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1986 }
1987
1988 void PF_cos (void)
1989 {
1990         G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1991 }
1992
1993 void PF_sqrt (void)
1994 {
1995         G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1996 }
1997
1998 /*
1999 =================
2000 PF_RandomVec
2001
2002 Returns a vector of length < 1
2003
2004 randomvec()
2005 =================
2006 */
2007 void PF_randomvec (void)
2008 {
2009         vec3_t          temp;
2010         do
2011         {
2012                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2013                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2014                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2015         }
2016         while (DotProduct(temp, temp) >= 1);
2017         VectorCopy (temp, G_VECTOR(OFS_RETURN));
2018 }
2019
2020 /*
2021 =================
2022 PF_GetLight
2023
2024 Returns a color vector indicating the lighting at the requested point.
2025
2026 (Internal Operation note: actually measures the light beneath the point, just like
2027                           the model lighting on the client)
2028
2029 getlight(vector)
2030 =================
2031 */
2032 void PF_GetLight (void)
2033 {
2034         vec3_t ambientcolor, diffusecolor, diffusenormal;
2035         vec_t *p;
2036         p = G_VECTOR(OFS_PARM0);
2037         VectorClear(ambientcolor);
2038         VectorClear(diffusecolor);
2039         VectorClear(diffusenormal);
2040         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2041                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2042         VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2043 }
2044
2045 void PF_registercvar (void)
2046 {
2047         char *name, *value;
2048         name = G_STRING(OFS_PARM0);
2049         value = G_STRING(OFS_PARM1);
2050         G_FLOAT(OFS_RETURN) = 0;
2051
2052 // first check to see if it has already been defined
2053         if (Cvar_FindVar (name))
2054                 return;
2055
2056 // check for overlap with a command
2057         if (Cmd_Exists (name))
2058         {
2059                 Con_Printf("PF_registercvar: %s is a command\n", name);
2060                 return;
2061         }
2062
2063         Cvar_Get(name, value, 0);
2064
2065         G_FLOAT(OFS_RETURN) = 1; // success
2066 }
2067
2068 /*
2069 =================
2070 PF_min
2071
2072 returns the minimum of two supplied floats
2073
2074 min(a, b)
2075 =================
2076 */
2077 void PF_min (void)
2078 {
2079         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2080         if (pr_argc == 2)
2081                 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2082         else if (pr_argc >= 3)
2083         {
2084                 int i;
2085                 float f = G_FLOAT(OFS_PARM0);
2086                 for (i = 1;i < pr_argc;i++)
2087                         if (G_FLOAT((OFS_PARM0+i*3)) < f)
2088                                 f = G_FLOAT((OFS_PARM0+i*3));
2089                 G_FLOAT(OFS_RETURN) = f;
2090         }
2091         else
2092         {
2093                 G_FLOAT(OFS_RETURN) = 0;
2094                 PF_WARNING("min: must supply at least 2 floats\n");
2095         }
2096 }
2097
2098 /*
2099 =================
2100 PF_max
2101
2102 returns the maximum of two supplied floats
2103
2104 max(a, b)
2105 =================
2106 */
2107 void PF_max (void)
2108 {
2109         // LordHavoc: 3+ argument enhancement suggested by FrikaC
2110         if (pr_argc == 2)
2111                 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2112         else if (pr_argc >= 3)
2113         {
2114                 int i;
2115                 float f = G_FLOAT(OFS_PARM0);
2116                 for (i = 1;i < pr_argc;i++)
2117                         if (G_FLOAT((OFS_PARM0+i*3)) > f)
2118                                 f = G_FLOAT((OFS_PARM0+i*3));
2119                 G_FLOAT(OFS_RETURN) = f;
2120         }
2121         else
2122         {
2123                 G_FLOAT(OFS_RETURN) = 0;
2124                 PF_WARNING("max: must supply at least 2 floats\n");
2125         }
2126 }
2127
2128 /*
2129 =================
2130 PF_bound
2131
2132 returns number bounded by supplied range
2133
2134 min(min, value, max)
2135 =================
2136 */
2137 void PF_bound (void)
2138 {
2139         G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2140 }
2141
2142 /*
2143 =================
2144 PF_pow
2145
2146 returns a raised to power b
2147
2148 pow(a, b)
2149 =================
2150 */
2151 void PF_pow (void)
2152 {
2153         G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2154 }
2155
2156 /*
2157 =================
2158 PF_copyentity
2159
2160 copies data from one entity to another
2161
2162 copyentity(src, dst)
2163 =================
2164 */
2165 void PF_copyentity (void)
2166 {
2167         edict_t *in, *out;
2168         in = G_EDICT(OFS_PARM0);
2169         if (in == sv.edicts)
2170                 PF_WARNING("copyentity: can not read world entity\n");
2171         if (in->e->free)
2172                 PF_WARNING("copyentity: can not read free entity\n");
2173         out = G_EDICT(OFS_PARM1);
2174         if (out == sv.edicts)
2175                 PF_WARNING("copyentity: can not modify world entity\n");
2176         if (out->e->free)
2177                 PF_WARNING("copyentity: can not modify free entity\n");
2178         memcpy(out->v, in->v, progs->entityfields * 4);
2179 }
2180
2181 /*
2182 =================
2183 PF_setcolor
2184
2185 sets the color of a client and broadcasts the update to all connected clients
2186
2187 setcolor(clientent, value)
2188 =================
2189 */
2190 void PF_setcolor (void)
2191 {
2192         client_t *client;
2193         int entnum, i;
2194         eval_t *val;
2195
2196         entnum = G_EDICTNUM(OFS_PARM0);
2197         i = G_FLOAT(OFS_PARM1);
2198
2199         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2200         {
2201                 Con_Print("tried to setcolor a non-client\n");
2202                 return;
2203         }
2204
2205         client = svs.clients + entnum-1;
2206         if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2207                 val->_float = i;
2208         client->colors = i;
2209         client->old_colors = i;
2210         client->edict->v->team = (i & 15) + 1;
2211
2212         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2213         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2214         MSG_WriteByte (&sv.reliable_datagram, i);
2215 }
2216
2217 /*
2218 =================
2219 PF_effect
2220
2221 effect(origin, modelname, startframe, framecount, framerate)
2222 =================
2223 */
2224 void PF_effect (void)
2225 {
2226         int i;
2227         char *s;
2228         s = G_STRING(OFS_PARM1);
2229         if (!s || !s[0])
2230                 PF_WARNING("effect: no model specified\n");
2231
2232         i = SV_ModelIndex(s);
2233         if (i < 0)
2234                 PF_WARNING("effect: model not precached\n");
2235         SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2236 }
2237
2238 void PF_te_blood (void)
2239 {
2240         if (G_FLOAT(OFS_PARM2) < 1)
2241                 return;
2242         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2243         MSG_WriteByte(&sv.datagram, TE_BLOOD);
2244         // origin
2245         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2246         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2247         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2248         // velocity
2249         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2250         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2251         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2252         // count
2253         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2254 }
2255
2256 void PF_te_bloodshower (void)
2257 {
2258         if (G_FLOAT(OFS_PARM3) < 1)
2259                 return;
2260         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2261         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2262         // min
2263         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2264         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2265         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2266         // max
2267         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2268         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2269         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2270         // speed
2271         MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2272         // count
2273         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2274 }
2275
2276 void PF_te_explosionrgb (void)
2277 {
2278         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2279         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2280         // origin
2281         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2282         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2283         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2284         // color
2285         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2286         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2287         MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2288 }
2289
2290 void PF_te_particlecube (void)
2291 {
2292         if (G_FLOAT(OFS_PARM3) < 1)
2293                 return;
2294         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2295         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2296         // min
2297         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2298         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2299         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2300         // max
2301         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2302         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2303         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2304         // velocity
2305         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2306         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2307         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2308         // count
2309         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2310         // color
2311         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2312         // gravity true/false
2313         MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2314         // randomvel
2315         MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2316 }
2317
2318 void PF_te_particlerain (void)
2319 {
2320         if (G_FLOAT(OFS_PARM3) < 1)
2321                 return;
2322         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2323         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2324         // min
2325         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2326         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2327         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2328         // max
2329         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2330         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2331         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2332         // velocity
2333         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2334         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2335         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2336         // count
2337         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2338         // color
2339         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2340 }
2341
2342 void PF_te_particlesnow (void)
2343 {
2344         if (G_FLOAT(OFS_PARM3) < 1)
2345                 return;
2346         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2347         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2348         // min
2349         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2350         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2351         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2352         // max
2353         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2354         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2355         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2356         // velocity
2357         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2358         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2359         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2360         // count
2361         MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2362         // color
2363         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2364 }
2365
2366 void PF_te_spark (void)
2367 {
2368         if (G_FLOAT(OFS_PARM2) < 1)
2369                 return;
2370         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2371         MSG_WriteByte(&sv.datagram, TE_SPARK);
2372         // origin
2373         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2374         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2375         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2376         // velocity
2377         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2378         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2379         MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2380         // count
2381         MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2382 }
2383
2384 void PF_te_gunshotquad (void)
2385 {
2386         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2387         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2388         // origin
2389         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2390         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2391         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2392 }
2393
2394 void PF_te_spikequad (void)
2395 {
2396         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2398         // origin
2399         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2400         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2401         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2402 }
2403
2404 void PF_te_superspikequad (void)
2405 {
2406         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2407         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2408         // origin
2409         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2410         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2411         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2412 }
2413
2414 void PF_te_explosionquad (void)
2415 {
2416         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2417         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2418         // origin
2419         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2420         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2421         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2422 }
2423
2424 void PF_te_smallflash (void)
2425 {
2426         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2427         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2428         // origin
2429         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2430         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2431         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2432 }
2433
2434 void PF_te_customflash (void)
2435 {
2436         if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2437                 return;
2438         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2439         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2440         // origin
2441         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2442         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2443         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2444         // radius
2445         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2446         // lifetime
2447         MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2448         // color
2449         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2450         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2451         MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2452 }
2453
2454 void PF_te_gunshot (void)
2455 {
2456         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2457         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2458         // origin
2459         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2460         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2461         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2462 }
2463
2464 void PF_te_spike (void)
2465 {
2466         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2467         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2468         // origin
2469         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2470         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2471         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2472 }
2473
2474 void PF_te_superspike (void)
2475 {
2476         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2477         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2478         // origin
2479         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2480         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2481         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2482 }
2483
2484 void PF_te_explosion (void)
2485 {
2486         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2487         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2488         // origin
2489         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2490         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2491         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2492 }
2493
2494 void PF_te_tarexplosion (void)
2495 {
2496         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2497         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2498         // origin
2499         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2500         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2501         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2502 }
2503
2504 void PF_te_wizspike (void)
2505 {
2506         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2507         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2508         // origin
2509         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2510         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2511         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2512 }
2513
2514 void PF_te_knightspike (void)
2515 {
2516         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2517         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2518         // origin
2519         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2520         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2521         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2522 }
2523
2524 void PF_te_lavasplash (void)
2525 {
2526         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2527         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2528         // origin
2529         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2530         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2531         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2532 }
2533
2534 void PF_te_teleport (void)
2535 {
2536         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2537         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2538         // origin
2539         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2540         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2541         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2542 }
2543
2544 void PF_te_explosion2 (void)
2545 {
2546         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2547         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2548         // origin
2549         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2550         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2551         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2552         // color
2553         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2554         MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2555 }
2556
2557 void PF_te_lightning1 (void)
2558 {
2559         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2560         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2561         // owner entity
2562         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2563         // start
2564         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2565         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2566         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2567         // end
2568         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2569         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2570         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2571 }
2572
2573 void PF_te_lightning2 (void)
2574 {
2575         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2576         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2577         // owner entity
2578         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2579         // start
2580         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2581         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2582         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2583         // end
2584         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2585         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2586         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2587 }
2588
2589 void PF_te_lightning3 (void)
2590 {
2591         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2592         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2593         // owner entity
2594         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2595         // start
2596         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2597         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2598         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2599         // end
2600         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2601         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2602         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2603 }
2604
2605 void PF_te_beam (void)
2606 {
2607         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2608         MSG_WriteByte(&sv.datagram, TE_BEAM);
2609         // owner entity
2610         MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2611         // start
2612         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2613         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2614         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2615         // end
2616         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2617         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2618         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2619 }
2620
2621 void PF_te_plasmaburn (void)
2622 {
2623         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2624         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2625         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2626         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2627         MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2628 }
2629
2630 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2631 {
2632         int i, j;
2633         vec3_t v1, clipplanenormal, normal;
2634         vec_t clipplanedist, clipdist;
2635         VectorCopy(p, out);
2636         if (surf->flags & SURF_PLANEBACK)
2637                 VectorNegate(surf->plane->normal, normal);
2638         else
2639                 VectorCopy(surf->plane->normal, normal);
2640         for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2641         {
2642                 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2643                 VectorNormalizeFast(v1);
2644                 CrossProduct(v1, normal, clipplanenormal);
2645                 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2646                 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2647                 if (clipdist > 0)
2648                 {
2649                         clipdist = -clipdist;
2650                         VectorMA(out, clipdist, clipplanenormal, out);
2651                 }
2652         }
2653 }
2654
2655 static msurface_t *getsurface(edict_t *ed, int surfnum)
2656 {
2657         int modelindex;
2658         model_t *model;
2659         if (!ed || ed->e->free)
2660                 return NULL;
2661         modelindex = ed->v->modelindex;
2662         if (modelindex < 1 || modelindex >= MAX_MODELS)
2663                 return NULL;
2664         model = sv.models[modelindex];
2665         if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2666                 return NULL;
2667         return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2668 }
2669
2670
2671 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2672 void PF_getsurfacenumpoints(void)
2673 {
2674         msurface_t *surf;
2675         // return 0 if no such surface
2676         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2677         {
2678                 G_FLOAT(OFS_RETURN) = 0;
2679                 return;
2680         }
2681
2682         G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2683 }
2684 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2685 void PF_getsurfacepoint(void)
2686 {
2687         edict_t *ed;
2688         msurface_t *surf;
2689         int pointnum;
2690         VectorClear(G_VECTOR(OFS_RETURN));
2691         ed = G_EDICT(OFS_PARM0);
2692         if (!ed || ed->e->free)
2693                 return;
2694         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2695                 return;
2696         pointnum = G_FLOAT(OFS_PARM2);
2697         if (pointnum < 0 || pointnum >= surf->poly_numverts)
2698                 return;
2699         // FIXME: implement rotation/scaling
2700         VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2701 }
2702 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2703 void PF_getsurfacenormal(void)
2704 {
2705         msurface_t *surf;
2706         VectorClear(G_VECTOR(OFS_RETURN));
2707         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2708                 return;
2709         // FIXME: implement rotation/scaling
2710         if (surf->flags & SURF_PLANEBACK)
2711                 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2712         else
2713                 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2714 }
2715 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2716 void PF_getsurfacetexture(void)
2717 {
2718         msurface_t *surf;
2719         G_INT(OFS_RETURN) = 0;
2720         if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2721                 return;
2722         G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2723 }
2724 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2725 void PF_getsurfacenearpoint(void)
2726 {
2727         int surfnum, best, modelindex;
2728         vec3_t clipped, p;
2729         vec_t dist, bestdist;
2730         edict_t *ed;
2731         model_t *model;
2732         msurface_t *surf;
2733         vec_t *point;
2734         G_FLOAT(OFS_RETURN) = -1;
2735         ed = G_EDICT(OFS_PARM0);
2736         point = G_VECTOR(OFS_PARM1);
2737
2738         if (!ed || ed->e->free)
2739                 return;
2740         modelindex = ed->v->modelindex;
2741         if (modelindex < 1 || modelindex >= MAX_MODELS)
2742                 return;
2743         model = sv.models[modelindex];
2744         if (!model->brushq1.numsurfaces)
2745                 return;
2746
2747         // FIXME: implement rotation/scaling
2748         VectorSubtract(point, ed->v->origin, p);
2749         best = -1;
2750         bestdist = 1000000000;
2751         for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2752         {
2753                 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2754                 dist = PlaneDiff(p, surf->plane);
2755                 dist = dist * dist;
2756                 if (dist < bestdist)
2757                 {
2758                         clippointtosurface(surf, p, clipped);
2759                         VectorSubtract(clipped, p, clipped);
2760                         dist += DotProduct(clipped, clipped);
2761                         if (dist < bestdist)
2762                         {
2763                                 best = surfnum;
2764                                 bestdist = dist;
2765                         }
2766                 }
2767         }
2768         G_FLOAT(OFS_RETURN) = best;
2769 }
2770 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2771 void PF_getsurfaceclippedpoint(void)
2772 {
2773         edict_t *ed;
2774         msurface_t *surf;
2775         vec3_t p, out;
2776         VectorClear(G_VECTOR(OFS_RETURN));
2777         ed = G_EDICT(OFS_PARM0);
2778         if (!ed || ed->e->free)
2779                 return;
2780         if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2781                 return;
2782         // FIXME: implement rotation/scaling
2783         VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2784         clippointtosurface(surf, p, out);
2785         // FIXME: implement rotation/scaling
2786         VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2787 }
2788
2789 #define MAX_PRFILES 256
2790
2791 qfile_t *pr_files[MAX_PRFILES];
2792
2793 void PR_Files_Init(void)
2794 {
2795         memset(pr_files, 0, sizeof(pr_files));
2796 }
2797
2798 void PR_Files_CloseAll(void)
2799 {
2800         int i;
2801         for (i = 0;i < MAX_PRFILES;i++)
2802         {
2803                 if (pr_files[i])
2804                         FS_Close(pr_files[i]);
2805                 pr_files[i] = NULL;
2806         }
2807 }
2808
2809 //float(string s) stof = #81; // get numerical value from a string
2810 void PF_stof(void)
2811 {
2812         char string[STRINGTEMP_LENGTH];
2813         PF_VarString(0, string, sizeof(string));
2814         G_FLOAT(OFS_RETURN) = atof(string);
2815 }
2816
2817 //float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
2818 void PF_fopen(void)
2819 {
2820         int filenum, mode, i;
2821         char *modestring, *filename;
2822         for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2823                 if (pr_files[filenum] == NULL)
2824                         break;
2825         if (filenum >= MAX_PRFILES)
2826         {
2827                 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2828                 G_FLOAT(OFS_RETURN) = -2;
2829                 return;
2830         }
2831         mode = G_FLOAT(OFS_PARM1);
2832         switch(mode)
2833         {
2834         case 0: // FILE_READ
2835                 modestring = "rb";
2836                 break;
2837         case 1: // FILE_APPEND
2838                 modestring = "ab";
2839                 break;
2840         case 2: // FILE_WRITE
2841                 modestring = "wb";
2842                 break;
2843         default:
2844                 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2845                 G_FLOAT(OFS_RETURN) = -3;
2846                 return;
2847         }
2848         filename = G_STRING(OFS_PARM0);
2849         // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2850         // ../ is parent directory on many platforms
2851         // // is parent directory on Amiga
2852         // / at the beginning of a path is root on unix, and parent directory on Amiga
2853         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2854         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2855         for (i = 0;filename[i];i++)
2856         {
2857                 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2858                 {
2859                         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);
2860                         G_FLOAT(OFS_RETURN) = -4;
2861                         return;
2862                 }
2863         }
2864         pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2865
2866         if (pr_files[filenum] == NULL && modestring == "rb")
2867                 pr_files[filenum] = FS_Open(filename, modestring, false);
2868
2869         if (pr_files[filenum] == NULL)
2870                 G_FLOAT(OFS_RETURN) = -1;
2871         else
2872                 G_FLOAT(OFS_RETURN) = filenum;
2873 }
2874
2875 //void(float fhandle) fclose = #111; // closes a file
2876 void PF_fclose(void)
2877 {
2878         int filenum = G_FLOAT(OFS_PARM0);
2879         if (filenum < 0 || filenum >= MAX_PRFILES)
2880         {
2881                 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2882                 return;
2883         }
2884         if (pr_files[filenum] == NULL)
2885         {
2886                 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2887                 return;
2888         }
2889         FS_Close(pr_files[filenum]);
2890         pr_files[filenum] = NULL;
2891 }
2892
2893 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2894 void PF_fgets(void)
2895 {
2896         int c, end;
2897         static char string[STRINGTEMP_LENGTH];
2898         int filenum = G_FLOAT(OFS_PARM0);
2899         if (filenum < 0 || filenum >= MAX_PRFILES)
2900         {
2901                 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2902                 return;
2903         }
2904         if (pr_files[filenum] == NULL)
2905         {
2906                 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2907                 return;
2908         }
2909         end = 0;
2910         for (;;)
2911         {
2912                 c = FS_Getc(pr_files[filenum]);
2913                 if (c == '\r' || c == '\n' || c < 0)
2914                         break;
2915                 if (end < STRINGTEMP_LENGTH - 1)
2916                         string[end++] = c;
2917         }
2918         string[end] = 0;
2919         // remove \n following \r
2920         if (c == '\r')
2921                 c = FS_Getc(pr_files[filenum]);
2922         if (developer.integer)
2923                 Con_Printf("fgets: %s\n", string);
2924         if (c >= 0 || end)
2925                 G_INT(OFS_RETURN) = PR_SetString(string);
2926         else
2927                 G_INT(OFS_RETURN) = 0;
2928 }
2929
2930 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2931 void PF_fputs(void)
2932 {
2933         int stringlength;
2934         char string[STRINGTEMP_LENGTH];
2935         int filenum = G_FLOAT(OFS_PARM0);
2936         if (filenum < 0 || filenum >= MAX_PRFILES)
2937         {
2938                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2939                 return;
2940         }
2941         if (pr_files[filenum] == NULL)
2942         {
2943                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2944                 return;
2945         }
2946         PF_VarString(1, string, sizeof(string));
2947         if ((stringlength = strlen(string)))
2948                 FS_Write(pr_files[filenum], string, stringlength);
2949         if (developer.integer)
2950                 Con_Printf("fputs: %s\n", string);
2951 }
2952
2953 //float(string s) strlen = #114; // returns how many characters are in a string
2954 void PF_strlen(void)
2955 {
2956         char *s;
2957         s = G_STRING(OFS_PARM0);
2958         if (s)
2959                 G_FLOAT(OFS_RETURN) = strlen(s);
2960         else
2961                 G_FLOAT(OFS_RETURN) = 0;
2962 }
2963
2964 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2965 void PF_strcat(void)
2966 {
2967         char *s = PR_GetTempString();
2968         PF_VarString(0, s, STRINGTEMP_LENGTH);
2969         G_INT(OFS_RETURN) = PR_SetString(s);
2970 }
2971
2972 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2973 void PF_substring(void)
2974 {
2975         int i, start, length;
2976         char *s, *string = PR_GetTempString();
2977         s = G_STRING(OFS_PARM0);
2978         start = G_FLOAT(OFS_PARM1);
2979         length = G_FLOAT(OFS_PARM2);
2980         if (!s)
2981                 s = "";
2982         for (i = 0;i < start && *s;i++, s++);
2983         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2984                 string[i] = *s;
2985         string[i] = 0;
2986         G_INT(OFS_RETURN) = PR_SetString(string);
2987 }
2988
2989 //vector(string s) stov = #117; // returns vector value from a string
2990 void PF_stov(void)
2991 {
2992         char string[STRINGTEMP_LENGTH];
2993         PF_VarString(0, string, sizeof(string));
2994         Math_atov(string, G_VECTOR(OFS_RETURN));
2995 }
2996
2997 //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)
2998 void PF_strzone(void)
2999 {
3000         char *in, *out;
3001         in = G_STRING(OFS_PARM0);
3002         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3003         strcpy(out, in);
3004         G_INT(OFS_RETURN) = PR_SetString(out);
3005 }
3006
3007 //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!!!)
3008 void PF_strunzone(void)
3009 {
3010         Mem_Free(G_STRING(OFS_PARM0));
3011 }
3012
3013 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3014 //this function originally written by KrimZon, made shorter by LordHavoc
3015 void PF_clientcommand (void)
3016 {
3017         client_t *temp_client;
3018         int i;
3019
3020         //find client for this entity
3021         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3022         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3023         {
3024                 Con_Print("PF_clientcommand: entity is not a client\n");
3025                 return;
3026         }
3027
3028         temp_client = host_client;
3029         host_client = svs.clients + i;
3030         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3031         host_client = temp_client;
3032 }
3033
3034 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3035 //this function originally written by KrimZon, made shorter by LordHavoc
3036 //20040203: rewritten by LordHavoc (no longer uses allocations)
3037 int num_tokens = 0;
3038 char *tokens[256], tokenbuf[4096];
3039 void PF_tokenize (void)
3040 {
3041         int pos;
3042         const char *p;
3043         p = G_STRING(OFS_PARM0);
3044
3045         num_tokens = 0;
3046         pos = 0;
3047         while(COM_ParseToken(&p, false))
3048         {
3049                 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3050                         break;
3051                 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3052                         break;
3053                 tokens[num_tokens++] = tokenbuf + pos;
3054                 strcpy(tokenbuf + pos, com_token);
3055                 pos += strlen(com_token) + 1;
3056         }
3057
3058         G_FLOAT(OFS_RETURN) = num_tokens;
3059 }
3060
3061 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3062 //this function originally written by KrimZon, made shorter by LordHavoc
3063 void PF_argv (void)
3064 {
3065         int token_num = G_FLOAT(OFS_PARM0);
3066         if (token_num >= 0 && token_num < num_tokens)
3067                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3068         else
3069                 G_INT(OFS_RETURN) = PR_SetString("");
3070 }
3071
3072 //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)
3073 void PF_setattachment (void)
3074 {
3075         edict_t *e = G_EDICT(OFS_PARM0);
3076         edict_t *tagentity = G_EDICT(OFS_PARM1);
3077         char *tagname = G_STRING(OFS_PARM2);
3078         eval_t *v;
3079         int i, modelindex;
3080         model_t *model;
3081
3082         if (e == sv.edicts)
3083                 PF_WARNING("setattachment: can not modify world entity\n");
3084         if (e->e->free)
3085                 PF_WARNING("setattachment: can not modify free entity\n");
3086
3087         if (tagentity == NULL)
3088                 tagentity = sv.edicts;
3089
3090         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3091         if (v)
3092                 v->edict = EDICT_TO_PROG(tagentity);
3093
3094         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3095         if (v)
3096                 v->_float = 0;
3097         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3098         {
3099                 modelindex = (int)tagentity->v->modelindex;
3100                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3101                 {
3102                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3103                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3104                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3105                                                 v->_float = i + 1;
3106                         // FIXME: use a model function to get tag info (need to handle skeletal)
3107                         if (v->_float == 0 && model->alias.aliasnum_tags)
3108                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3109                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3110                                                 v->_float = i + 1;
3111                         if (v->_float == 0)
3112                                 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);
3113                 }
3114                 else
3115                         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));
3116         }
3117 }
3118
3119
3120 /////////////////////////////////////////
3121 // DP_QC_FS_SEARCH extension
3122
3123 // qc fs search handling
3124 #define MAX_SEARCHES 128
3125
3126 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3127
3128 void PR_Search_Init(void)
3129 {
3130         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3131 }
3132
3133 void PR_Search_Reset(void)
3134 {
3135         int i;
3136         // reset the fssearch list
3137         for(i = 0; i < MAX_SEARCHES; i++)
3138                 if(pr_fssearchlist[i])
3139                         FS_FreeSearch(pr_fssearchlist[i]);
3140         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3141 }
3142
3143 /*
3144 =========
3145 PF_search_begin
3146
3147 float search_begin(string pattern, float caseinsensitive, float quiet)
3148 =========
3149 */
3150 void PF_search_begin(void)
3151 {
3152         int handle;
3153         char *pattern;
3154         int caseinsens, quiet;
3155
3156         pattern = G_STRING(OFS_PARM0);
3157
3158         PR_CheckEmptyString(pattern);
3159
3160         caseinsens = G_FLOAT(OFS_PARM1);
3161         quiet = G_FLOAT(OFS_PARM2);
3162         
3163         for(handle = 0; handle < MAX_SEARCHES; handle++)
3164                 if(!pr_fssearchlist[handle])
3165                         break;
3166
3167         if(handle >= MAX_SEARCHES)
3168         {
3169                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3170                 G_FLOAT(OFS_RETURN) = -2;
3171                 return;
3172         }
3173
3174         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3175                 G_FLOAT(OFS_RETURN) = -1;
3176         else
3177                 G_FLOAT(OFS_RETURN) = handle;
3178 }
3179
3180 /*
3181 =========
3182 VM_search_end
3183
3184 void    search_end(float handle)
3185 =========
3186 */
3187 void PF_search_end(void)
3188 {
3189         int handle;
3190
3191         handle = G_FLOAT(OFS_PARM0);
3192         
3193         if(handle < 0 || handle >= MAX_SEARCHES)
3194         {
3195                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3196                 return;
3197         }
3198         if(pr_fssearchlist[handle] == NULL)
3199         {
3200                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3201                 return;
3202         }
3203
3204         FS_FreeSearch(pr_fssearchlist[handle]);
3205         pr_fssearchlist[handle] = NULL;
3206 }
3207
3208 /*
3209 =========
3210 VM_search_getsize
3211
3212 float   search_getsize(float handle)
3213 =========
3214 */
3215 void PF_search_getsize(void)
3216 {
3217         int handle;
3218
3219         handle = G_FLOAT(OFS_PARM0);
3220
3221         if(handle < 0 || handle >= MAX_SEARCHES)
3222         {
3223                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3224                 return;
3225         }
3226         if(pr_fssearchlist[handle] == NULL)
3227         {
3228                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3229                 return;
3230         }
3231         
3232         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3233 }
3234
3235 /*
3236 =========
3237 VM_search_getfilename
3238
3239 string  search_getfilename(float handle, float num)
3240 =========
3241 */
3242 void PF_search_getfilename(void)
3243 {
3244         int handle, filenum;
3245         char *tmp;
3246
3247         handle = G_FLOAT(OFS_PARM0);
3248         filenum = G_FLOAT(OFS_PARM1);
3249
3250         if(handle < 0 || handle >= MAX_SEARCHES)
3251         {
3252                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3253                 return;
3254         }
3255         if(pr_fssearchlist[handle] == NULL)
3256         {
3257                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3258                 return;
3259         }
3260         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3261         {
3262                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3263                 return;
3264         }
3265         
3266         tmp = PR_GetTempString();
3267         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3268
3269         G_INT(OFS_RETURN) = PR_SetString(tmp);
3270 }
3271
3272 void PF_cvar_string (void)
3273 {
3274         char *str;
3275         cvar_t *var;
3276         char *tmp;
3277
3278         str = G_STRING(OFS_PARM0);
3279         var = Cvar_FindVar (str);
3280
3281         tmp = PR_GetTempString();
3282         strcpy(tmp, var->string);
3283
3284         G_INT(OFS_RETURN) = PR_SetString(tmp);
3285 }
3286
3287
3288
3289 builtin_t pr_builtin[] =
3290 {
3291 NULL,                                           // #0
3292 PF_makevectors,                         // #1 void(entity e) makevectors
3293 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3294 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3295 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3296 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3297 PF_break,                                       // #6 void() break
3298 PF_random,                                      // #7 float() random
3299 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3300 PF_normalize,                           // #9 vector(vector v) normalize
3301 PF_error,                                       // #10 void(string e) error
3302 PF_objerror,                            // #11 void(string e) objerror
3303 PF_vlen,                                        // #12 float(vector v) vlen
3304 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3305 PF_Spawn,                                       // #14 entity() spawn
3306 PF_Remove,                                      // #15 void(entity e) remove
3307 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3308 PF_checkclient,                         // #17 entity() clientlist
3309 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3310 PF_precache_sound,                      // #19 void(string s) precache_sound
3311 PF_precache_model,                      // #20 void(string s) precache_model
3312 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3313 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3314 PF_bprint,                                      // #23 void(string s) bprint
3315 PF_sprint,                                      // #24 void(entity client, string s) sprint
3316 PF_dprint,                                      // #25 void(string s) dprint
3317 PF_ftos,                                        // #26 void(string s) ftos
3318 PF_vtos,                                        // #27 void(string s) vtos
3319 PF_coredump,                            // #28 void() coredump
3320 PF_traceon,                                     // #29 void() traceon
3321 PF_traceoff,                            // #30 void() traceoff
3322 PF_eprint,                                      // #31 void(entity e) eprint
3323 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3324 NULL,                                           // #33
3325 PF_droptofloor,                         // #34 float() droptofloor
3326 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3327 PF_rint,                                        // #36 float(float v) rint
3328 PF_floor,                                       // #37 float(float v) floor
3329 PF_ceil,                                        // #38 float(float v) ceil
3330 NULL,                                           // #39
3331 PF_checkbottom,                         // #40 float(entity e) checkbottom
3332 PF_pointcontents                ,       // #41 float(vector v) pointcontents
3333 NULL,                                           // #42
3334 PF_fabs,                                        // #43 float(float f) fabs
3335 PF_aim,                                         // #44 vector(entity e, float speed) aim
3336 PF_cvar,                                        // #45 float(string s) cvar
3337 PF_localcmd,                            // #46 void(string s) localcmd
3338 PF_nextent,                                     // #47 entity(entity e) nextent
3339 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3340 PF_changeyaw,                           // #49 void() ChangeYaw
3341 NULL,                                           // #50
3342 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3343 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3344 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3345 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3346 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3347 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3348 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3349 PF_WriteString,                         // #58 void(float to, string s) WriteString
3350 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3351 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3352 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3353 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3354 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3355 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3356 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3357 NULL,                                           // #66
3358 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3359 PF_precache_file,                       // #68 string(string s) precache_file
3360 PF_makestatic,                          // #69 void(entity e) makestatic
3361 PF_changelevel,                         // #70 void(string s) changelevel
3362 NULL,                                           // #71
3363 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3364 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3365 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3366 PF_precache_model,                      // #75 string(string s) precache_model2
3367 PF_precache_sound,                      // #76 string(string s) precache_sound2
3368 PF_precache_file,                       // #77 string(string s) precache_file2
3369 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3370 NULL,                                           // #79
3371 NULL,                                           // #80
3372 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3373 NULL,                                           // #82
3374 NULL,                                           // #83
3375 NULL,                                           // #84
3376 NULL,                                           // #85
3377 NULL,                                           // #86
3378 NULL,                                           // #87
3379 NULL,                                           // #88
3380 NULL,                                           // #89
3381 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3382 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3383 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3384 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3385 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3386 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3387 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3388 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3389 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3390 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3391 NULL,                                           // #100
3392 NULL,                                           // #101
3393 NULL,                                           // #102
3394 NULL,                                           // #103
3395 NULL,                                           // #104
3396 NULL,                                           // #105
3397 NULL,                                           // #106
3398 NULL,                                           // #107
3399 NULL,                                           // #108
3400 NULL,                                           // #109
3401 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3402 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3403 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3404 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3405 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3406 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3407 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3408 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3409 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3410 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3411 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3412 a a a a a a a a                         // #120-199
3413 a a a a a a a a a a                     // #200-299
3414 a a a a a a a a a a                     // #300-399
3415 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3416 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3417 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3418 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3419 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3420 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3421 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3422 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3423 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3424 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3425 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3426 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3427 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3428 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3429 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3430 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3431 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3432 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3433 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3434 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3435 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3436 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3437 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3438 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3439 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3440 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3441 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3442 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3443 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3444 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3445 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3446 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3447 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3448 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3449 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3450 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3451 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3452 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3453 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3454 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3455 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3456 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3457 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3458 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3459 PF_search_begin,                        // #444
3460 PF_search_end,                          // #445
3461 PF_search_getsize,                      // #446
3462 PF_search_getfilename,          // #447
3463 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3464 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3465 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3466 NULL,                                           // #451
3467 NULL,                                           // #452
3468 NULL,                                           // #453
3469 NULL,                                           // #454
3470 NULL,                                           // #455
3471 NULL,                                           // #456
3472 NULL,                                           // #457
3473 NULL,                                           // #458
3474 NULL,                                           // #459
3475 a a a a                                         // #460-499 (LordHavoc)
3476 };
3477
3478 builtin_t *pr_builtins = pr_builtin;
3479 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3480
3481 void PR_Cmd_Init(void)
3482 {
3483         pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3484         PR_Files_Init();
3485         PR_Search_Init();
3486 }
3487
3488 void PR_Cmd_Reset(void)
3489 {
3490         Mem_EmptyPool(pr_strings_mempool);
3491         PR_Search_Reset();
3492         PR_Files_CloseAll();
3493 }
3494