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