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