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