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