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