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