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