]> icculus.org git repositories - divverent/darkplaces.git/blob - pr_cmds.c
added support for skill values outside the range 0-3
[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         {
2880                 c = FS_Getc(pr_files[filenum]);
2881                 if (c != '\n')
2882                         FS_UnGetc(pr_files[filenum], (unsigned char)c);
2883         }
2884         if (developer.integer)
2885                 Con_Printf("fgets: %s\n", string);
2886         if (c >= 0 || end)
2887                 G_INT(OFS_RETURN) = PR_SetString(string);
2888         else
2889                 G_INT(OFS_RETURN) = 0;
2890 }
2891
2892 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2893 void PF_fputs(void)
2894 {
2895         int stringlength;
2896         char string[STRINGTEMP_LENGTH];
2897         int filenum = G_FLOAT(OFS_PARM0);
2898         if (filenum < 0 || filenum >= MAX_PRFILES)
2899         {
2900                 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2901                 return;
2902         }
2903         if (pr_files[filenum] == NULL)
2904         {
2905                 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2906                 return;
2907         }
2908         PF_VarString(1, string, sizeof(string));
2909         if ((stringlength = strlen(string)))
2910                 FS_Write(pr_files[filenum], string, stringlength);
2911         if (developer.integer)
2912                 Con_Printf("fputs: %s\n", string);
2913 }
2914
2915 //float(string s) strlen = #114; // returns how many characters are in a string
2916 void PF_strlen(void)
2917 {
2918         char *s;
2919         s = G_STRING(OFS_PARM0);
2920         if (s)
2921                 G_FLOAT(OFS_RETURN) = strlen(s);
2922         else
2923                 G_FLOAT(OFS_RETURN) = 0;
2924 }
2925
2926 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2927 void PF_strcat(void)
2928 {
2929         char *s = PR_GetTempString();
2930         PF_VarString(0, s, STRINGTEMP_LENGTH);
2931         G_INT(OFS_RETURN) = PR_SetString(s);
2932 }
2933
2934 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2935 void PF_substring(void)
2936 {
2937         int i, start, length;
2938         char *s, *string = PR_GetTempString();
2939         s = G_STRING(OFS_PARM0);
2940         start = G_FLOAT(OFS_PARM1);
2941         length = G_FLOAT(OFS_PARM2);
2942         if (!s)
2943                 s = "";
2944         for (i = 0;i < start && *s;i++, s++);
2945         for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2946                 string[i] = *s;
2947         string[i] = 0;
2948         G_INT(OFS_RETURN) = PR_SetString(string);
2949 }
2950
2951 //vector(string s) stov = #117; // returns vector value from a string
2952 void PF_stov(void)
2953 {
2954         char string[STRINGTEMP_LENGTH];
2955         PF_VarString(0, string, sizeof(string));
2956         Math_atov(string, G_VECTOR(OFS_RETURN));
2957 }
2958
2959 //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)
2960 void PF_strzone(void)
2961 {
2962         char *in, *out;
2963         in = G_STRING(OFS_PARM0);
2964         out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2965         strcpy(out, in);
2966         G_INT(OFS_RETURN) = PR_SetString(out);
2967 }
2968
2969 //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!!!)
2970 void PF_strunzone(void)
2971 {
2972         Mem_Free(G_STRING(OFS_PARM0));
2973 }
2974
2975 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2976 //this function originally written by KrimZon, made shorter by LordHavoc
2977 void PF_clientcommand (void)
2978 {
2979         client_t *temp_client;
2980         int i;
2981
2982         //find client for this entity
2983         i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2984         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2985         {
2986                 Con_Print("PF_clientcommand: entity is not a client\n");
2987                 return;
2988         }
2989
2990         temp_client = host_client;
2991         host_client = svs.clients + i;
2992         Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2993         host_client = temp_client;
2994 }
2995
2996 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2997 //this function originally written by KrimZon, made shorter by LordHavoc
2998 //20040203: rewritten by LordHavoc (no longer uses allocations)
2999 int num_tokens = 0;
3000 char *tokens[256], tokenbuf[4096];
3001 void PF_tokenize (void)
3002 {
3003         int pos;
3004         const char *p;
3005         p = G_STRING(OFS_PARM0);
3006
3007         num_tokens = 0;
3008         pos = 0;
3009         while(COM_ParseToken(&p, false))
3010         {
3011                 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3012                         break;
3013                 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3014                         break;
3015                 tokens[num_tokens++] = tokenbuf + pos;
3016                 strcpy(tokenbuf + pos, com_token);
3017                 pos += strlen(com_token) + 1;
3018         }
3019
3020         G_FLOAT(OFS_RETURN) = num_tokens;
3021 }
3022
3023 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3024 //this function originally written by KrimZon, made shorter by LordHavoc
3025 void PF_argv (void)
3026 {
3027         int token_num = G_FLOAT(OFS_PARM0);
3028         if (token_num >= 0 && token_num < num_tokens)
3029                 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3030         else
3031                 G_INT(OFS_RETURN) = PR_SetString("");
3032 }
3033
3034 //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)
3035 void PF_setattachment (void)
3036 {
3037         edict_t *e = G_EDICT(OFS_PARM0);
3038         edict_t *tagentity = G_EDICT(OFS_PARM1);
3039         char *tagname = G_STRING(OFS_PARM2);
3040         eval_t *v;
3041         int i, modelindex;
3042         model_t *model;
3043
3044         if (e == sv.edicts)
3045                 PF_WARNING("setattachment: can not modify world entity\n");
3046         if (e->e->free)
3047                 PF_WARNING("setattachment: can not modify free entity\n");
3048
3049         if (tagentity == NULL)
3050                 tagentity = sv.edicts;
3051
3052         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3053         if (v)
3054                 v->edict = EDICT_TO_PROG(tagentity);
3055
3056         v = GETEDICTFIELDVALUE(e, eval_tag_index);
3057         if (v)
3058                 v->_float = 0;
3059         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3060         {
3061                 modelindex = (int)tagentity->v->modelindex;
3062                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3063                 {
3064                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3065                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3066                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3067                                                 v->_float = i + 1;
3068                         // FIXME: use a model function to get tag info (need to handle skeletal)
3069                         if (v->_float == 0 && model->alias.aliasnum_tags)
3070                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
3071                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3072                                                 v->_float = i + 1;
3073                         if (v->_float == 0)
3074                                 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);
3075                 }
3076                 else
3077                         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));
3078         }
3079 }
3080
3081 /////////////////////////////////////////
3082 // DP_MD3_TAGINFO extension coded by VorteX
3083
3084 int SV_GetTagIndex (edict_t *e, char *tagname)
3085 {
3086         int tagindex, i;
3087         model_t *model;
3088
3089         i = e->v->modelindex;
3090         if (i < 1 || i >= MAX_MODELS)
3091                 return -1;
3092         model = sv.models[i];
3093
3094         tagindex = -1;
3095         if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3096         {
3097                 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3098                 {
3099                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3100                         {
3101                                 tagindex = i;
3102                                 break;
3103                         }
3104                 }
3105         }
3106         if (tagindex == -1)
3107         {
3108                 for (i = 0;i < model->alias.aliasnum_tags; i++)
3109                 {
3110                         if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3111                         {
3112                                 tagindex = i;
3113                                 break;
3114                         }
3115                 }
3116         }
3117         return tagindex + 1;
3118 };
3119
3120 // Warnings/errors code:
3121 // 0 - normal (everything all-right)
3122 // 1 - world entity
3123 // 2 - free entity
3124 // 3 - null or non-precached model
3125 // 4 - no tags with requested index
3126 // 5 - runaway loop at attachment chain
3127 extern cvar_t cl_bob;
3128 extern cvar_t cl_bobcycle;
3129 extern cvar_t cl_bobup;
3130 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3131 {
3132         eval_t *val;
3133         int modelindex, reqtag, reqframe, attachloop;
3134         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3135         edict_t *attachent;
3136         model_t *model;
3137
3138         Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3139
3140         if (ent == sv.edicts)
3141                 return 1;
3142         if (ent->e->free)
3143                 return 2;
3144
3145         modelindex = (int)ent->v->modelindex;
3146         if (modelindex <= 0 || modelindex > MAX_MODELS)
3147                 return 3;
3148
3149         model = sv.models[modelindex];
3150         reqtag = model->alias.aliasnum_tags;
3151
3152         if (tagindex <= 0 || tagindex > reqtag)
3153         {
3154                 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3155                         return 4;
3156                 return 0;
3157         }
3158
3159         if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3160                 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3161         else
3162                 reqframe = ent->v->frame;
3163
3164         // get initial tag matrix
3165         if (tagindex)
3166         {
3167                 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3168                 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3169         }
3170         else
3171                 Matrix4x4_CreateIdentity(&tagmatrix);
3172
3173         if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3174         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3175                 attachloop = 0;
3176                 do
3177                 {
3178                         attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3179                         val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3180                         Matrix4x4_CreateIdentity(&attachmatrix);
3181                         if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS)
3182                         {
3183                                 model = sv.models[(int)attachent->v->modelindex];
3184                                 if (val->_float < model->alias.aliasnum_tags)
3185                                 {
3186                                         // got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3187                                         model = sv.models[(int)attachent->v->modelindex];
3188                                         reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3189                                         Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3190                                 }
3191                         }
3192
3193                         // apply transformation by child entity matrix
3194                         val = GETEDICTFIELDVALUE(ent, eval_scale);
3195                         if (val->_float == 0)
3196                                 val->_float = 1;
3197                         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);
3198                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3199                         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]);
3200                         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]);
3201                         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]);
3202                         Matrix4x4_Copy(&tagmatrix, out);
3203
3204                         // finally transformate by matrix of tag on parent entity
3205                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3206                         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];
3207                         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];
3208                         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];
3209                         Matrix4x4_Copy(&tagmatrix, out);
3210
3211                         ent = attachent;
3212                         attachloop += 1;
3213                         if (attachloop > 255) // prevent runaway looping
3214                                 return 5;
3215                 }
3216                 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3217         }
3218
3219         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3220         val = GETEDICTFIELDVALUE(ent, eval_scale);
3221         if (val->_float == 0)
3222                 val->_float = 1;
3223         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3224         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);
3225         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3226         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]);
3227         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]);
3228         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]);
3229
3230         if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3231         {// RENDER_VIEWMODEL magic
3232                 Matrix4x4_Copy(&tagmatrix, out);
3233                 ent = EDICT_NUM(val->edict);
3234
3235                 val = GETEDICTFIELDVALUE(ent, eval_scale);
3236                 if (val->_float == 0)
3237                         val->_float = 1;
3238
3239                 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);
3240                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3241                 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]);
3242                 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]);
3243                 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]);
3244
3245                 /*
3246                 // Cl_bob, ported from rendering code
3247                 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3248                 {
3249                         double bob, cycle;
3250                         // LordHavoc: this code is *weird*, but not replacable (I think it
3251                         // should be done in QC on the server, but oh well, quake is quake)
3252                         // LordHavoc: figured out bobup: the time at which the sin is at 180
3253                         // degrees (which allows lengthening or squishing the peak or valley)
3254                         cycle = sv.time/cl_bobcycle.value;
3255                         cycle -= (int)cycle;
3256                         if (cycle < cl_bobup.value)
3257                                 cycle = sin(M_PI * cycle / cl_bobup.value);
3258                         else
3259                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3260                         // bob is proportional to velocity in the xy plane
3261                         // (don't count Z, or jumping messes it up)
3262                         bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3263                         bob = bob*0.3 + bob*0.7*cycle;
3264                         out->m[2][3] += bound(-7, bob, 4);
3265                 }
3266                 */
3267         }
3268         return 0;
3269 }
3270
3271 //float(entity ent, string tagname) gettagindex;
3272
3273 void PF_gettagindex (void)
3274 {
3275         edict_t *ent = G_EDICT(OFS_PARM0);
3276         char *tag_name = G_STRING(OFS_PARM1);
3277         int modelindex, tag_index;
3278
3279         if (ent == sv.edicts)
3280                 PF_WARNING("gettagindex: can't affect world entity\n");
3281         if (ent->e->free)
3282                 PF_WARNING("gettagindex: can't affect free entity\n");
3283
3284         modelindex = (int)ent->v->modelindex;
3285         tag_index = 0;
3286         if (modelindex <= 0 || modelindex > MAX_MODELS)
3287                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3288         else
3289         {
3290                 tag_index = SV_GetTagIndex(ent, tag_name);
3291                 if (tag_index == 0)
3292                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3293         }
3294         G_FLOAT(OFS_RETURN) = tag_index;
3295 };
3296
3297 //vector(entity ent, float tagindex) gettaginfo;
3298 void PF_gettaginfo (void)
3299 {
3300         edict_t *e = G_EDICT(OFS_PARM0);
3301         int tagindex = (int)G_FLOAT(OFS_PARM1);
3302         matrix4x4_t tag_matrix;
3303         int returncode;
3304
3305         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3306         Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3307
3308         switch(returncode)
3309         {
3310                 case 1:
3311                         PF_WARNING("gettagindex: can't affect world entity\n");
3312                         break;
3313                 case 2:
3314                         PF_WARNING("gettagindex: can't affect free entity\n");
3315                         break;
3316                 case 3:
3317                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3318                         break;
3319                 case 4:
3320                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3321                         break;
3322                 case 5:
3323                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3324                         break;
3325         }
3326 }
3327
3328
3329 /////////////////////////////////////////
3330 // DP_QC_FS_SEARCH extension
3331
3332 // qc fs search handling
3333 #define MAX_SEARCHES 128
3334
3335 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3336
3337 void PR_Search_Init(void)
3338 {
3339         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3340 }
3341
3342 void PR_Search_Reset(void)
3343 {
3344         int i;
3345         // reset the fssearch list
3346         for(i = 0; i < MAX_SEARCHES; i++)
3347                 if(pr_fssearchlist[i])
3348                         FS_FreeSearch(pr_fssearchlist[i]);
3349         memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3350 }
3351
3352 /*
3353 =========
3354 PF_search_begin
3355
3356 float search_begin(string pattern, float caseinsensitive, float quiet)
3357 =========
3358 */
3359 void PF_search_begin(void)
3360 {
3361         int handle;
3362         char *pattern;
3363         int caseinsens, quiet;
3364
3365         pattern = G_STRING(OFS_PARM0);
3366
3367         PR_CheckEmptyString(pattern);
3368
3369         caseinsens = G_FLOAT(OFS_PARM1);
3370         quiet = G_FLOAT(OFS_PARM2);
3371
3372         for(handle = 0; handle < MAX_SEARCHES; handle++)
3373                 if(!pr_fssearchlist[handle])
3374                         break;
3375
3376         if(handle >= MAX_SEARCHES)
3377         {
3378                 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3379                 G_FLOAT(OFS_RETURN) = -2;
3380                 return;
3381         }
3382
3383         if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3384                 G_FLOAT(OFS_RETURN) = -1;
3385         else
3386                 G_FLOAT(OFS_RETURN) = handle;
3387 }
3388
3389 /*
3390 =========
3391 VM_search_end
3392
3393 void    search_end(float handle)
3394 =========
3395 */
3396 void PF_search_end(void)
3397 {
3398         int handle;
3399
3400         handle = G_FLOAT(OFS_PARM0);
3401
3402         if(handle < 0 || handle >= MAX_SEARCHES)
3403         {
3404                 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3405                 return;
3406         }
3407         if(pr_fssearchlist[handle] == NULL)
3408         {
3409                 Con_Printf("PF_search_end: no such handle %i\n", handle);
3410                 return;
3411         }
3412
3413         FS_FreeSearch(pr_fssearchlist[handle]);
3414         pr_fssearchlist[handle] = NULL;
3415 }
3416
3417 /*
3418 =========
3419 VM_search_getsize
3420
3421 float   search_getsize(float handle)
3422 =========
3423 */
3424 void PF_search_getsize(void)
3425 {
3426         int handle;
3427
3428         handle = G_FLOAT(OFS_PARM0);
3429
3430         if(handle < 0 || handle >= MAX_SEARCHES)
3431         {
3432                 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3433                 return;
3434         }
3435         if(pr_fssearchlist[handle] == NULL)
3436         {
3437                 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3438                 return;
3439         }
3440
3441         G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3442 }
3443
3444 /*
3445 =========
3446 VM_search_getfilename
3447
3448 string  search_getfilename(float handle, float num)
3449 =========
3450 */
3451 void PF_search_getfilename(void)
3452 {
3453         int handle, filenum;
3454         char *tmp;
3455
3456         handle = G_FLOAT(OFS_PARM0);
3457         filenum = G_FLOAT(OFS_PARM1);
3458
3459         if(handle < 0 || handle >= MAX_SEARCHES)
3460         {
3461                 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3462                 return;
3463         }
3464         if(pr_fssearchlist[handle] == NULL)
3465         {
3466                 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3467                 return;
3468         }
3469         if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3470         {
3471                 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3472                 return;
3473         }
3474
3475         tmp = PR_GetTempString();
3476         strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3477
3478         G_INT(OFS_RETURN) = PR_SetString(tmp);
3479 }
3480
3481 void PF_cvar_string (void)
3482 {
3483         char *str;
3484         cvar_t *var;
3485         char *tmp;
3486
3487         str = G_STRING(OFS_PARM0);
3488         var = Cvar_FindVar (str);
3489         if (var)
3490         {
3491                 tmp = PR_GetTempString();
3492                 strcpy(tmp, var->string);
3493         }
3494         else
3495                 tmp = "";
3496         G_INT(OFS_RETURN) = PR_SetString(tmp);
3497 }
3498
3499 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3500 void PF_dropclient (void)
3501 {
3502         int clientnum;
3503         client_t *oldhostclient;
3504         clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3505         if (clientnum < 0 || clientnum >= svs.maxclients)
3506                 PF_WARNING("dropclient: not a client\n");
3507         if (!svs.clients[clientnum].active)
3508                 PF_WARNING("dropclient: that client slot is not connected\n");
3509         oldhostclient = host_client;
3510         host_client = svs.clients + clientnum;
3511         SV_DropClient(false);
3512         host_client = oldhostclient;
3513 }
3514
3515 //entity() spawnclient (DP_SV_BOTCLIENT)
3516 void PF_spawnclient (void)
3517 {
3518         int i;
3519         edict_t *ed;
3520         pr_xfunction->builtinsprofile += 2;
3521         ed = sv.edicts;
3522         for (i = 0;i < svs.maxclients;i++)
3523         {
3524                 if (!svs.clients[i].active)
3525                 {
3526                         pr_xfunction->builtinsprofile += 100;
3527                         SV_ConnectClient (i, NULL);
3528                         ed = EDICT_NUM(i + 1);
3529                         break;
3530                 }
3531         }
3532         RETURN_EDICT(ed);
3533 }
3534
3535 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3536 void PF_clienttype (void)
3537 {
3538         int clientnum;
3539         clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3540         if (clientnum < 0 || clientnum >= svs.maxclients)
3541                 G_FLOAT(OFS_RETURN) = 3;
3542         else if (!svs.clients[clientnum].active)
3543                 G_FLOAT(OFS_RETURN) = 0;
3544         else if (svs.clients[clientnum].netconnection)
3545                 G_FLOAT(OFS_RETURN) = 1;
3546         else
3547                 G_FLOAT(OFS_RETURN) = 2;
3548 }
3549
3550 builtin_t pr_builtin[] =
3551 {
3552 NULL,                                           // #0
3553 PF_makevectors,                         // #1 void(entity e) makevectors
3554 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
3555 PF_setmodel,                            // #3 void(entity e, string m) setmodel
3556 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
3557 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
3558 PF_break,                                       // #6 void() break
3559 PF_random,                                      // #7 float() random
3560 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
3561 PF_normalize,                           // #9 vector(vector v) normalize
3562 PF_error,                                       // #10 void(string e) error
3563 PF_objerror,                            // #11 void(string e) objerror
3564 PF_vlen,                                        // #12 float(vector v) vlen
3565 PF_vectoyaw,                            // #13 float(vector v) vectoyaw
3566 PF_Spawn,                                       // #14 entity() spawn
3567 PF_Remove,                                      // #15 void(entity e) remove
3568 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
3569 PF_checkclient,                         // #17 entity() clientlist
3570 PF_Find,                                        // #18 entity(entity start, .string fld, string match) find
3571 PF_precache_sound,                      // #19 void(string s) precache_sound
3572 PF_precache_model,                      // #20 void(string s) precache_model
3573 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
3574 PF_findradius,                          // #22 entity(vector org, float rad) findradius
3575 PF_bprint,                                      // #23 void(string s) bprint
3576 PF_sprint,                                      // #24 void(entity client, string s) sprint
3577 PF_dprint,                                      // #25 void(string s) dprint
3578 PF_ftos,                                        // #26 void(string s) ftos
3579 PF_vtos,                                        // #27 void(string s) vtos
3580 PF_coredump,                            // #28 void() coredump
3581 PF_traceon,                                     // #29 void() traceon
3582 PF_traceoff,                            // #30 void() traceoff
3583 PF_eprint,                                      // #31 void(entity e) eprint
3584 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
3585 NULL,                                           // #33
3586 PF_droptofloor,                         // #34 float() droptofloor
3587 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
3588 PF_rint,                                        // #36 float(float v) rint
3589 PF_floor,                                       // #37 float(float v) floor
3590 PF_ceil,                                        // #38 float(float v) ceil
3591 NULL,                                           // #39
3592 PF_checkbottom,                         // #40 float(entity e) checkbottom
3593 PF_pointcontents,                       // #41 float(vector v) pointcontents
3594 NULL,                                           // #42
3595 PF_fabs,                                        // #43 float(float f) fabs
3596 PF_aim,                                         // #44 vector(entity e, float speed) aim
3597 PF_cvar,                                        // #45 float(string s) cvar
3598 PF_localcmd,                            // #46 void(string s) localcmd
3599 PF_nextent,                                     // #47 entity(entity e) nextent
3600 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
3601 PF_changeyaw,                           // #49 void() ChangeYaw
3602 NULL,                                           // #50
3603 PF_vectoangles,                         // #51 vector(vector v) vectoangles
3604 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
3605 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
3606 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
3607 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
3608 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
3609 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
3610 PF_WriteString,                         // #58 void(float to, string s) WriteString
3611 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
3612 PF_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3613 PF_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3614 PF_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3615 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3616 PF_TraceToss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3617 PF_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
3618 NULL,                                           // #66
3619 SV_MoveToGoal,                          // #67 void(float step) movetogoal
3620 PF_precache_file,                       // #68 string(string s) precache_file
3621 PF_makestatic,                          // #69 void(entity e) makestatic
3622 PF_changelevel,                         // #70 void(string s) changelevel
3623 NULL,                                           // #71
3624 PF_cvar_set,                            // #72 void(string var, string val) cvar_set
3625 PF_centerprint,                         // #73 void(entity client, strings) centerprint
3626 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3627 PF_precache_model,                      // #75 string(string s) precache_model2
3628 PF_precache_sound,                      // #76 string(string s) precache_sound2
3629 PF_precache_file,                       // #77 string(string s) precache_file2
3630 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
3631 NULL,                                           // #79
3632 NULL,                                           // #80
3633 PF_stof,                                        // #81 float(string s) stof (FRIK_FILE)
3634 NULL,                                           // #82
3635 NULL,                                           // #83
3636 NULL,                                           // #84
3637 NULL,                                           // #85
3638 NULL,                                           // #86
3639 NULL,                                           // #87
3640 NULL,                                           // #88
3641 NULL,                                           // #89
3642 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3643 PF_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
3644 PF_GetLight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3645 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3646 PF_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3647 PF_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3648 PF_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3649 PF_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3650 PF_FindFloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3651 PF_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
3652 NULL,                                           // #100
3653 NULL,                                           // #101
3654 NULL,                                           // #102
3655 NULL,                                           // #103
3656 NULL,                                           // #104
3657 NULL,                                           // #105
3658 NULL,                                           // #106
3659 NULL,                                           // #107
3660 NULL,                                           // #108
3661 NULL,                                           // #109
3662 PF_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
3663 PF_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
3664 PF_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
3665 PF_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3666 PF_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
3667 PF_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
3668 PF_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
3669 PF_stov,                                        // #117 vector(string) stov (FRIK_FILE)
3670 PF_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
3671 PF_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
3672 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3673 a a a a a a a a                         // #120-199
3674 a a a a a a a a a a                     // #200-299
3675 a a a a a a a a a a                     // #300-399
3676 PF_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3677 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3678 PF_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3679 PF_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3680 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3681 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3682 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3683 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3684 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3685 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3686 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3687 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3688 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3689 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3690 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3691 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3692 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3693 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3694 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3695 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3696 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3697 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3698 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3699 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3700 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3701 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3702 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3703 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3704 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3705 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3706 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3707 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3708 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3709 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3710 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3711 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3712 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3713 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3714 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3715 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3716 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3717 PF_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3718 PF_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3719 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3720 PF_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3721 PF_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
3722 PF_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3723 PF_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3724 PF_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3725 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3726 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3727 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3728 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3729 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3730 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3731 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3732 NULL,                                           // #456
3733 NULL,                                           // #457
3734 NULL,                                           // #458
3735 NULL,                                           // #459
3736 a a a a                                         // #460-499 (LordHavoc)
3737 };
3738
3739 builtin_t *pr_builtins = pr_builtin;
3740 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3741
3742 void PR_Cmd_Init(void)
3743 {
3744         pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3745         PR_Files_Init();
3746         PR_Search_Init();
3747 }
3748
3749 void PR_Cmd_Shutdown(void)
3750 {
3751         Mem_FreePool (&pr_strings_mempool);
3752 }
3753
3754 void PR_Cmd_Reset(void)
3755 {
3756         Mem_EmptyPool(pr_strings_mempool);
3757         PR_Search_Reset();
3758         PR_Files_CloseAll();
3759 }
3760