]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - svvm_cmds.c
removed two unused Key_Event implementations (which let me remove some unused variabl...
[xonotic/darkplaces.git] / svvm_cmds.c
1 #include "prvm_cmds.h"
2
3 //============================================================================
4 // Server
5
6 #define PF_WARNING(s) do{Con_Printf(s);PRVM_PrintState();return;}while(0)
7 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
8
9
10 char *vm_sv_extensions =
11 "DP_BUTTONCHAT "
12 "DP_BUTTONUSE "
13 "DP_CL_LOADSKY "
14 "DP_CON_SET "
15 "DP_CON_SETA "
16 "DP_CON_STARTMAP "
17 "DP_EF_ADDITIVE "
18 "DP_EF_BLUE "
19 "DP_EF_FLAME "
20 "DP_EF_FULLBRIGHT "
21 "DP_EF_NODEPTHTEST "
22 "DP_EF_NODRAW "
23 "DP_EF_NOSHADOW "
24 "DP_EF_RED "
25 "DP_EF_STARDUST "
26 "DP_ENT_ALPHA "
27 "DP_ENT_CUSTOMCOLORMAP "
28 "DP_ENT_EXTERIORMODELTOCLIENT "
29 "DP_ENT_GLOW "
30 "DP_ENT_LOWPRECISION "
31 "DP_ENT_SCALE "
32 "DP_ENT_VIEWMODEL "
33 "DP_GFX_EXTERNALTEXTURES "
34 "DP_GFX_FOG "
35 "DP_GFX_QUAKE3MODELTAGS "
36 "DP_GFX_SKINFILES "
37 "DP_GFX_SKYBOX "
38 "DP_HALFLIFE_MAP "
39 "DP_HALFLIFE_MAP_CVAR "
40 "DP_HALFLIFE_SPRITE "
41 "DP_INPUTBUTTONS "
42 "DP_LITSPRITES "
43 "DP_LITSUPPORT "
44 "DP_MONSTERWALK "
45 "DP_MOVETYPEBOUNCEMISSILE "
46 "DP_MOVETYPEFOLLOW "
47 "DP_QC_CHANGEPITCH "
48 "DP_QC_COPYENTITY "
49 "DP_QC_CVAR_STRING "
50 "DP_QC_ETOS "
51 "DP_QC_FINDCHAIN "
52 "DP_QC_FINDCHAINFLAGS "
53 "DP_QC_FINDCHAINFLOAT "
54 "DP_QC_FINDFLAGS "
55 "DP_QC_FINDFLOAT "
56 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
57 "DP_QC_GETLIGHT "
58 "DP_QC_GETSURFACE "
59 "DP_QC_GETTAGINFO "
60 "DP_QC_MINMAXBOUND "
61 "DP_QC_MULTIPLETEMPSTRINGS "
62 "DP_QC_RANDOMVEC "
63 "DP_QC_SINCOSSQRTPOW "
64 "DP_QC_TRACEBOX "
65 "DP_QC_TRACETOSS "
66 "DP_QC_TRACE_MOVETYPE_HITMODEL "
67 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
68 "DP_QC_VECTORVECTORS "
69 "DP_QUAKE2_MODEL "
70 "DP_QUAKE2_SPRITE "
71 "DP_QUAKE3_MAP "
72 "DP_QUAKE3_MODEL "
73 "DP_REGISTERCVAR "
74 "DP_SND_DIRECTIONLESSATTNNONE "
75 "DP_SND_FAKETRACKS "
76 "DP_SND_OGGVORBIS "
77 "DP_SND_STEREOWAV "
78 "DP_SOLIDCORPSE "
79 "DP_SPRITE32 "
80 "DP_SV_BOTCLIENT "
81 "DP_SV_CLIENTCOLORS "
82 "DP_SV_CLIENTNAME "
83 "DP_SV_DRAWONLYTOCLIENT "
84 "DP_SV_DROPCLIENT "
85 "DP_SV_EFFECT "
86 "DP_SV_NODRAWTOCLIENT "
87 "DP_SV_PING "
88 "DP_SV_PLAYERPHYSICS "
89 "DP_SV_PUNCHVECTOR "
90 "DP_SV_ROTATINGBMODEL "
91 "DP_SV_SETCOLOR "
92 "DP_SV_SLOWMO "
93 "DP_TE_BLOOD "
94 "DP_TE_BLOODSHOWER "
95 "DP_TE_CUSTOMFLASH "
96 "DP_TE_EXPLOSIONRGB "
97 "DP_TE_FLAMEJET "
98 "DP_TE_PARTICLECUBE "
99 "DP_TE_PARTICLERAIN "
100 "DP_TE_PARTICLESNOW "
101 "DP_TE_PLASMABURN "
102 "DP_TE_QUADEFFECTS1 "
103 "DP_TE_SMALLFLASH "
104 "DP_TE_SPARK "
105 "DP_TE_STANDARDEFFECTBUILTINS "
106 "DP_VIEWZOOM "
107 "FRIK_FILE "
108 "KRIMZON_SV_PARSECLIENTCOMMAND "
109 "NEH_CMD_PLAY2 "
110 "NEH_RESTOREGAME "
111 "NXQ_GFX_LETTERBOX "
112 "PRYDON_CLIENTCURSOR "
113 "TENEBRAE_GFX_DLIGHTS "
114 "TW_SV_STEPCONTROL "
115 "NEXUIZ_PLAYERMODEL "
116 "NEXUIZ_PLAYERSKIN "
117 ;
118
119 /*
120 ==============
121 PF_makevectors
122
123 Writes new values for v_forward, v_up, and v_right based on angles
124 makevectors(vector)
125 ==============
126 */
127 void PF_makevectors (void)
128 {
129         AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
130 }
131
132 /*
133 ==============
134 PF_vectorvectors
135
136 Writes new values for v_forward, v_up, and v_right based on the given forward vector
137 vectorvectors(vector, vector)
138 ==============
139 */
140 void PF_vectorvectors (void)
141 {
142         VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward);
143         VectorVectors(prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
144 }
145
146 /*
147 =================
148 PF_setorigin
149
150 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.
151
152 setorigin (entity, origin)
153 =================
154 */
155 void PF_setorigin (void)
156 {
157         prvm_edict_t    *e;
158         float   *org;
159
160         e = PRVM_G_EDICT(OFS_PARM0);
161         if (e == prog->edicts)
162                 PF_WARNING("setorigin: can not modify world entity\n");
163         if (e->priv.server->free)
164                 PF_WARNING("setorigin: can not modify free entity\n");
165         org = PRVM_G_VECTOR(OFS_PARM1);
166         VectorCopy (org, e->fields.server->origin);
167         SV_LinkEdict (e, false);
168 }
169
170
171 void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
172 {
173         int             i;
174
175         for (i=0 ; i<3 ; i++)
176                 if (min[i] > max[i])
177                         PRVM_ERROR("SetMinMaxSize: backwards mins/maxs\n");
178
179 // set derived values
180         VectorCopy (min, e->fields.server->mins);
181         VectorCopy (max, e->fields.server->maxs);
182         VectorSubtract (max, min, e->fields.server->size);
183
184         SV_LinkEdict (e, false);
185 }
186
187 /*
188 =================
189 PF_setsize
190
191 the size box is rotated by the current angle
192 LordHavoc: no it isn't...
193
194 setsize (entity, minvector, maxvector)
195 =================
196 */
197 void PF_setsize (void)
198 {
199         prvm_edict_t    *e;
200         float   *min, *max;
201
202         e = PRVM_G_EDICT(OFS_PARM0);
203         if (e == prog->edicts)
204                 PF_WARNING("setsize: can not modify world entity\n");
205         if (e->priv.server->free)
206                 PF_WARNING("setsize: can not modify free entity\n");
207         min = PRVM_G_VECTOR(OFS_PARM1);
208         max = PRVM_G_VECTOR(OFS_PARM2);
209         SetMinMaxSize (e, min, max, false);
210 }
211
212
213 /*
214 =================
215 PF_setmodel
216
217 setmodel(entity, model)
218 =================
219 */
220 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
221 void PF_setmodel (void)
222 {
223         prvm_edict_t    *e;
224         model_t *mod;
225         int             i;
226
227         e = PRVM_G_EDICT(OFS_PARM0);
228         if (e == prog->edicts)
229                 PF_WARNING("setmodel: can not modify world entity\n");
230         if (e->priv.server->free)
231                 PF_WARNING("setmodel: can not modify free entity\n");
232         i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
233         e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
234         e->fields.server->modelindex = i;
235
236         mod = sv.models[i];
237
238         if (mod)
239         {
240                 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
241                         SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
242                 else
243                         SetMinMaxSize (e, quakemins, quakemaxs, true);
244         }
245         else
246                 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
247 }
248
249 /*
250 =================
251 PF_sprint
252
253 single print to a specific client
254
255 sprint(clientent, value)
256 =================
257 */
258 void PF_sprint (void)
259 {
260         client_t        *client;
261         int                     entnum;
262         char string[VM_STRINGTEMP_LENGTH];
263
264         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
265
266         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
267         {
268                 Con_Print("tried to sprint to a non-client\n");
269                 return;
270         }
271
272         client = svs.clients + entnum-1;
273         VM_VarString(1, string, sizeof(string));
274         MSG_WriteChar(&client->message,svc_print);
275         MSG_WriteString(&client->message, string);
276 }
277
278
279 /*
280 =================
281 PF_centerprint
282
283 single print to a specific client
284
285 centerprint(clientent, value)
286 =================
287 */
288 void PF_centerprint (void)
289 {
290         client_t        *client;
291         int                     entnum;
292         char string[VM_STRINGTEMP_LENGTH];
293
294         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
295
296         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
297         {
298                 Con_Print("tried to sprint to a non-client\n");
299                 return;
300         }
301
302         client = svs.clients + entnum-1;
303         VM_VarString(1, string, sizeof(string));
304         MSG_WriteChar(&client->message,svc_centerprint);
305         MSG_WriteString(&client->message, string);
306 }
307
308 /*
309 =================
310 PF_particle
311
312 particle(origin, color, count)
313 =================
314 */
315 void PF_particle (void)
316 {
317         float           *org, *dir;
318         float           color;
319         float           count;
320
321         org = PRVM_G_VECTOR(OFS_PARM0);
322         dir = PRVM_G_VECTOR(OFS_PARM1);
323         color = PRVM_G_FLOAT(OFS_PARM2);
324         count = PRVM_G_FLOAT(OFS_PARM3);
325         SV_StartParticle (org, dir, color, count);
326 }
327
328
329 /*
330 =================
331 PF_ambientsound
332
333 =================
334 */
335 void PF_ambientsound (void)
336 {
337         const char      *samp;
338         float           *pos;
339         float           vol, attenuation;
340         int                     soundnum, large;
341
342         pos = PRVM_G_VECTOR (OFS_PARM0);
343         samp = PRVM_G_STRING(OFS_PARM1);
344         vol = PRVM_G_FLOAT(OFS_PARM2);
345         attenuation = PRVM_G_FLOAT(OFS_PARM3);
346
347 // check to see if samp was properly precached
348         soundnum = SV_SoundIndex(samp, 1);
349         if (!soundnum)
350                 return;
351
352         large = false;
353         if (soundnum >= 256)
354                 large = true;
355
356         // add an svc_spawnambient command to the level signon packet
357
358         if (large)
359                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
360         else
361                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
362
363         MSG_WriteVector(&sv.signon, pos, sv.protocol);
364
365         if (large)
366                 MSG_WriteShort (&sv.signon, soundnum);
367         else
368                 MSG_WriteByte (&sv.signon, soundnum);
369
370         MSG_WriteByte (&sv.signon, vol*255);
371         MSG_WriteByte (&sv.signon, attenuation*64);
372
373 }
374
375 /*
376 =================
377 PF_sound
378
379 Each entity can have eight independant sound sources, like voice,
380 weapon, feet, etc.
381
382 Channel 0 is an auto-allocate channel, the others override anything
383 already running on that entity/channel pair.
384
385 An attenuation of 0 will play full volume everywhere in the level.
386 Larger attenuations will drop off.
387
388 =================
389 */
390 void PF_sound (void)
391 {
392         const char      *sample;
393         int                     channel;
394         prvm_edict_t            *entity;
395         int             volume;
396         float attenuation;
397
398         entity = PRVM_G_EDICT(OFS_PARM0);
399         channel = PRVM_G_FLOAT(OFS_PARM1);
400         sample = PRVM_G_STRING(OFS_PARM2);
401         volume = PRVM_G_FLOAT(OFS_PARM3) * 255;
402         attenuation = PRVM_G_FLOAT(OFS_PARM4);
403
404         if (volume < 0 || volume > 255)
405                 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
406
407         if (attenuation < 0 || attenuation > 4)
408                 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
409
410         if (channel < 0 || channel > 7)
411                 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
412
413         SV_StartSound (entity, channel, sample, volume, attenuation);
414 }
415
416 /*
417 =================
418 PF_traceline
419
420 Used for use tracing and shot targeting
421 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
422 if the tryents flag is set.
423
424 traceline (vector1, vector2, tryents)
425 =================
426 */
427 void PF_traceline (void)
428 {
429         float   *v1, *v2;
430         trace_t trace;
431         int             move;
432         prvm_edict_t    *ent;
433
434         prog->xfunction->builtinsprofile += 30;
435
436         v1 = PRVM_G_VECTOR(OFS_PARM0);
437         v2 = PRVM_G_VECTOR(OFS_PARM1);
438         move = PRVM_G_FLOAT(OFS_PARM2);
439         ent = PRVM_G_EDICT(OFS_PARM3);
440
441         trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
442
443         prog->globals.server->trace_allsolid = trace.allsolid;
444         prog->globals.server->trace_startsolid = trace.startsolid;
445         prog->globals.server->trace_fraction = trace.fraction;
446         prog->globals.server->trace_inwater = trace.inwater;
447         prog->globals.server->trace_inopen = trace.inopen;
448         VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
449         VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
450         prog->globals.server->trace_plane_dist =  trace.plane.dist;
451         if (trace.ent)
452                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
453         else
454                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
455         // FIXME: add trace_endcontents
456 }
457
458
459 /*
460 =================
461 PF_tracebox
462
463 Used for use tracing and shot targeting
464 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
465 if the tryents flag is set.
466
467 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
468 =================
469 */
470 // LordHavoc: added this for my own use, VERY useful, similar to traceline
471 void PF_tracebox (void)
472 {
473         float   *v1, *v2, *m1, *m2;
474         trace_t trace;
475         int             move;
476         prvm_edict_t    *ent;
477
478         prog->xfunction->builtinsprofile += 30;
479
480         v1 = PRVM_G_VECTOR(OFS_PARM0);
481         m1 = PRVM_G_VECTOR(OFS_PARM1);
482         m2 = PRVM_G_VECTOR(OFS_PARM2);
483         v2 = PRVM_G_VECTOR(OFS_PARM3);
484         move = PRVM_G_FLOAT(OFS_PARM4);
485         ent = PRVM_G_EDICT(OFS_PARM5);
486
487         trace = SV_Move (v1, m1, m2, v2, move, ent);
488
489         prog->globals.server->trace_allsolid = trace.allsolid;
490         prog->globals.server->trace_startsolid = trace.startsolid;
491         prog->globals.server->trace_fraction = trace.fraction;
492         prog->globals.server->trace_inwater = trace.inwater;
493         prog->globals.server->trace_inopen = trace.inopen;
494         VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
495         VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
496         prog->globals.server->trace_plane_dist =  trace.plane.dist;
497         if (trace.ent)
498                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
499         else
500                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
501 }
502
503 extern trace_t SV_Trace_Toss (prvm_edict_t *ent, prvm_edict_t *ignore);
504 void PF_tracetoss (void)
505 {
506         trace_t trace;
507         prvm_edict_t    *ent;
508         prvm_edict_t    *ignore;
509
510         prog->xfunction->builtinsprofile += 600;
511
512         ent = PRVM_G_EDICT(OFS_PARM0);
513         if (ent == prog->edicts)
514                 PF_WARNING("tracetoss: can not use world entity\n");
515         ignore = PRVM_G_EDICT(OFS_PARM1);
516
517         trace = SV_Trace_Toss (ent, ignore);
518
519         prog->globals.server->trace_allsolid = trace.allsolid;
520         prog->globals.server->trace_startsolid = trace.startsolid;
521         prog->globals.server->trace_fraction = trace.fraction;
522         prog->globals.server->trace_inwater = trace.inwater;
523         prog->globals.server->trace_inopen = trace.inopen;
524         VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
525         VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
526         prog->globals.server->trace_plane_dist =  trace.plane.dist;
527         if (trace.ent)
528                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
529         else
530                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
531 }
532
533
534 /*
535 =================
536 PF_checkpos
537
538 Returns true if the given entity can move to the given position from it's
539 current position by walking or rolling.
540 FIXME: make work...
541 scalar checkpos (entity, vector)
542 =================
543 */
544 void PF_checkpos (void)
545 {
546 }
547
548 //============================================================================
549
550 int checkpvsbytes;
551 qbyte checkpvs[MAX_MAP_LEAFS/8];
552
553 int PF_newcheckclient (int check)
554 {
555         int             i;
556         prvm_edict_t    *ent;
557         vec3_t  org;
558
559 // cycle to the next one
560
561         check = bound(1, check, svs.maxclients);
562         if (check == svs.maxclients)
563                 i = 1;
564         else
565                 i = check + 1;
566
567         for ( ;  ; i++)
568         {
569                 // count the cost
570                 prog->xfunction->builtinsprofile++;
571                 // wrap around
572                 if (i == svs.maxclients+1)
573                         i = 1;
574                 // look up the client's edict
575                 ent = PRVM_EDICT_NUM(i);
576                 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
577                 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
578                         continue;
579                 // found a valid client (possibly the same one again)
580                 break;
581         }
582
583 // get the PVS for the entity
584         VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
585         checkpvsbytes = 0;
586         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
587                 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
588
589         return i;
590 }
591
592 /*
593 =================
594 PF_checkclient
595
596 Returns a client (or object that has a client enemy) that would be a
597 valid target.
598
599 If there is more than one valid option, they are cycled each frame
600
601 If (self.origin + self.viewofs) is not in the PVS of the current target,
602 it is not returned at all.
603
604 name checkclient ()
605 =================
606 */
607 int c_invis, c_notvis;
608 void PF_checkclient (void)
609 {
610         prvm_edict_t    *ent, *self;
611         vec3_t  view;
612
613         // find a new check if on a new frame
614         if (sv.time - sv.lastchecktime >= 0.1)
615         {
616                 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
617                 sv.lastchecktime = sv.time;
618         }
619
620         // return check if it might be visible
621         ent = PRVM_EDICT_NUM(sv.lastcheck);
622         if (ent->priv.server->free || ent->fields.server->health <= 0)
623         {
624                 VM_RETURN_EDICT(prog->edicts);
625                 return;
626         }
627
628         // if current entity can't possibly see the check entity, return 0
629         self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
630         VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
631         if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
632         {
633                 c_notvis++;
634                 VM_RETURN_EDICT(prog->edicts);
635                 return;
636         }
637
638         // might be able to see it
639         c_invis++;
640         VM_RETURN_EDICT(ent);
641 }
642
643 //============================================================================
644
645
646 /*
647 =================
648 PF_stuffcmd
649
650 Sends text over to the client's execution buffer
651
652 stuffcmd (clientent, value)
653 =================
654 */
655 void PF_stuffcmd (void)
656 {
657         int             entnum;
658         const char      *str;
659         client_t        *old;
660
661         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
662         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
663         {
664                 Con_Print("Can't stuffcmd to a non-client\n");
665                 return;
666         }
667         str = PRVM_G_STRING(OFS_PARM1);
668
669         old = host_client;
670         host_client = svs.clients + entnum-1;
671         Host_ClientCommands ("%s", str);
672         host_client = old;
673 }
674
675 /*
676 =================
677 PF_findradius
678
679 Returns a chain of entities that have origins within a spherical area
680
681 findradius (origin, radius)
682 =================
683 */
684 void PF_findradius (void)
685 {
686         prvm_edict_t *ent, *chain;
687         vec_t radius, radius2;
688         vec3_t org, eorg, mins, maxs;
689         int i;
690         int numtouchedicts;
691         prvm_edict_t *touchedicts[MAX_EDICTS];
692
693         chain = (prvm_edict_t *)prog->edicts;
694
695         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
696         radius = PRVM_G_FLOAT(OFS_PARM1);
697         radius2 = radius * radius;
698
699         mins[0] = org[0] - (radius + 1);
700         mins[1] = org[1] - (radius + 1);
701         mins[2] = org[2] - (radius + 1);
702         maxs[0] = org[0] + (radius + 1);
703         maxs[1] = org[1] + (radius + 1);
704         maxs[2] = org[2] + (radius + 1);
705         numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
706         if (numtouchedicts > MAX_EDICTS)
707         {
708                 // this never happens
709                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
710                 numtouchedicts = MAX_EDICTS;
711         }
712         for (i = 0;i < numtouchedicts;i++)
713         {
714                 ent = touchedicts[i];
715                 prog->xfunction->builtinsprofile++;
716                 // Quake did not return non-solid entities but darkplaces does
717                 // (note: this is the reason you can't blow up fallen zombies)
718                 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
719                         continue;
720                 // LordHavoc: compare against bounding box rather than center so it
721                 // doesn't miss large objects, and use DotProduct instead of Length
722                 // for a major speedup
723                 VectorSubtract(org, ent->fields.server->origin, eorg);
724                 if (sv_gameplayfix_findradiusdistancetobox.integer)
725                 {
726                         eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
727                         eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
728                         eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
729                 }
730                 else
731                         VectorMAMAM(1, eorg, 0.5f, ent->fields.server->mins, 0.5f, ent->fields.server->maxs, eorg);
732                 if (DotProduct(eorg, eorg) < radius2)
733                 {
734                         ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
735                         chain = ent;
736                 }
737         }
738
739         VM_RETURN_EDICT(chain);
740 }
741
742 // LordHavoc: search for flags in float fields
743 void PF_findflags (void)
744 {
745         int             e;
746         int             f;
747         int             s;
748         prvm_edict_t    *ed;
749
750         e = PRVM_G_EDICTNUM(OFS_PARM0);
751         f = PRVM_G_INT(OFS_PARM1);
752         s = (int)PRVM_G_FLOAT(OFS_PARM2);
753
754         for (e++ ; e < prog->num_edicts ; e++)
755         {
756                 prog->xfunction->builtinsprofile++;
757                 ed = PRVM_EDICT_NUM(e);
758                 if (ed->priv.server->free)
759                         continue;
760                 if ((int)PRVM_E_FLOAT(ed,f) & s)
761                 {
762                         VM_RETURN_EDICT(ed);
763                         return;
764                 }
765         }
766
767         VM_RETURN_EDICT(prog->edicts);
768 }
769
770 // LordHavoc: chained search for flags in float fields
771 void PF_findchainflags (void)
772 {
773         int             i;
774         int             f;
775         int             s;
776         prvm_edict_t    *ent, *chain;
777
778         chain = (prvm_edict_t *)prog->edicts;
779
780         f = PRVM_G_INT(OFS_PARM0);
781         s = (int)PRVM_G_FLOAT(OFS_PARM1);
782
783         ent = PRVM_NEXT_EDICT(prog->edicts);
784         for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
785         {
786                 prog->xfunction->builtinsprofile++;
787                 if (ent->priv.server->free)
788                         continue;
789                 if (!((int)PRVM_E_FLOAT(ent,f) & s))
790                         continue;
791
792                 ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
793                 chain = ent;
794         }
795
796         VM_RETURN_EDICT(chain);
797 }
798
799 void PF_precache_file (void)
800 {       // precache_file is only used to copy files with qcc, it does nothing
801         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
802 }
803
804
805 void PF_precache_sound (void)
806 {
807         SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
808         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
809 }
810
811 void PF_precache_model (void)
812 {
813         SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
814         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
815 }
816
817 /*
818 ===============
819 PF_walkmove
820
821 float(float yaw, float dist) walkmove
822 ===============
823 */
824 void PF_walkmove (void)
825 {
826         prvm_edict_t    *ent;
827         float   yaw, dist;
828         vec3_t  move;
829         mfunction_t     *oldf;
830         int     oldself;
831
832         // assume failure if it returns early
833         PRVM_G_FLOAT(OFS_RETURN) = 0;
834
835         ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
836         if (ent == prog->edicts)
837                 PF_WARNING("walkmove: can not modify world entity\n");
838         if (ent->priv.server->free)
839                 PF_WARNING("walkmove: can not modify free entity\n");
840         yaw = PRVM_G_FLOAT(OFS_PARM0);
841         dist = PRVM_G_FLOAT(OFS_PARM1);
842
843         if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
844                 return;
845
846         yaw = yaw*M_PI*2 / 360;
847
848         move[0] = cos(yaw)*dist;
849         move[1] = sin(yaw)*dist;
850         move[2] = 0;
851
852 // save program state, because SV_movestep may call other progs
853         oldf = prog->xfunction;
854         oldself = prog->globals.server->self;
855
856         PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
857
858
859 // restore program state
860         prog->xfunction = oldf;
861         prog->globals.server->self = oldself;
862 }
863
864 /*
865 ===============
866 PF_droptofloor
867
868 void() droptofloor
869 ===============
870 */
871 void PF_droptofloor (void)
872 {
873         prvm_edict_t            *ent;
874         vec3_t          end;
875         trace_t         trace;
876
877         // assume failure if it returns early
878         PRVM_G_FLOAT(OFS_RETURN) = 0;
879
880         ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
881         if (ent == prog->edicts)
882                 PF_WARNING("droptofloor: can not modify world entity\n");
883         if (ent->priv.server->free)
884                 PF_WARNING("droptofloor: can not modify free entity\n");
885
886         VectorCopy (ent->fields.server->origin, end);
887         end[2] -= 256;
888
889         trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent);
890
891         if (trace.fraction != 1)
892         {
893                 VectorCopy (trace.endpos, ent->fields.server->origin);
894                 SV_LinkEdict (ent, false);
895                 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
896                 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
897                 PRVM_G_FLOAT(OFS_RETURN) = 1;
898                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
899                 ent->priv.server->suspendedinairflag = true;
900         }
901 }
902
903 /*
904 ===============
905 PF_lightstyle
906
907 void(float style, string value) lightstyle
908 ===============
909 */
910 void PF_lightstyle (void)
911 {
912         int             style;
913         const char      *val;
914         client_t        *client;
915         int                     j;
916
917         style = PRVM_G_FLOAT(OFS_PARM0);
918         val = PRVM_G_STRING(OFS_PARM1);
919
920 // change the string in sv
921         strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
922
923 // send message to all clients on this server
924         if (sv.state != ss_active)
925                 return;
926
927         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
928         {
929                 if (client->active)
930                 {
931                         MSG_WriteChar (&client->message, svc_lightstyle);
932                         MSG_WriteChar (&client->message,style);
933                         MSG_WriteString (&client->message, val);
934                 }
935         }
936 }
937
938 /*
939 =============
940 PF_checkbottom
941 =============
942 */
943 void PF_checkbottom (void)
944 {
945         PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
946 }
947
948 /*
949 =============
950 PF_pointcontents
951 =============
952 */
953 void PF_pointcontents (void)
954 {
955         PRVM_G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(PRVM_G_VECTOR(OFS_PARM0));
956 }
957
958 /*
959 =============
960 PF_aim
961
962 Pick a vector for the player to shoot along
963 vector aim(entity, missilespeed)
964 =============
965 */
966 void PF_aim (void)
967 {
968         prvm_edict_t    *ent, *check, *bestent;
969         vec3_t  start, dir, end, bestdir;
970         int             i, j;
971         trace_t tr;
972         float   dist, bestdist;
973         float   speed;
974
975         // assume failure if it returns early
976         VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
977         // if sv_aim is so high it can't possibly accept anything, skip out early
978         if (sv_aim.value >= 1)
979                 return;
980
981         ent = PRVM_G_EDICT(OFS_PARM0);
982         if (ent == prog->edicts)
983                 PF_WARNING("aim: can not use world entity\n");
984         if (ent->priv.server->free)
985                 PF_WARNING("aim: can not use free entity\n");
986         speed = PRVM_G_FLOAT(OFS_PARM1);
987
988         VectorCopy (ent->fields.server->origin, start);
989         start[2] += 20;
990
991 // try sending a trace straight
992         VectorCopy (prog->globals.server->v_forward, dir);
993         VectorMA (start, 2048, dir, end);
994         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
995         if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
996         && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
997         {
998                 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
999                 return;
1000         }
1001
1002
1003 // try all possible entities
1004         VectorCopy (dir, bestdir);
1005         bestdist = sv_aim.value;
1006         bestent = NULL;
1007
1008         check = PRVM_NEXT_EDICT(prog->edicts);
1009         for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1010         {
1011                 prog->xfunction->builtinsprofile++;
1012                 if (check->fields.server->takedamage != DAMAGE_AIM)
1013                         continue;
1014                 if (check == ent)
1015                         continue;
1016                 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1017                         continue;       // don't aim at teammate
1018                 for (j=0 ; j<3 ; j++)
1019                         end[j] = check->fields.server->origin[j]
1020                         + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1021                 VectorSubtract (end, start, dir);
1022                 VectorNormalize (dir);
1023                 dist = DotProduct (dir, prog->globals.server->v_forward);
1024                 if (dist < bestdist)
1025                         continue;       // to far to turn
1026                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1027                 if (tr.ent == check)
1028                 {       // can shoot at this one
1029                         bestdist = dist;
1030                         bestent = check;
1031                 }
1032         }
1033
1034         if (bestent)
1035         {
1036                 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1037                 dist = DotProduct (dir, prog->globals.server->v_forward);
1038                 VectorScale (prog->globals.server->v_forward, dist, end);
1039                 end[2] = dir[2];
1040                 VectorNormalize (end);
1041                 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1042         }
1043         else
1044         {
1045                 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1046         }
1047 }
1048
1049 /*
1050 ==============
1051 PF_changeyaw
1052
1053 This was a major timewaster in progs, so it was converted to C
1054 ==============
1055 */
1056 void PF_changeyaw (void)
1057 {
1058         prvm_edict_t            *ent;
1059         float           ideal, current, move, speed;
1060
1061         ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1062         if (ent == prog->edicts)
1063                 PF_WARNING("changeyaw: can not modify world entity\n");
1064         if (ent->priv.server->free)
1065                 PF_WARNING("changeyaw: can not modify free entity\n");
1066         current = ANGLEMOD(ent->fields.server->angles[1]);
1067         ideal = ent->fields.server->ideal_yaw;
1068         speed = ent->fields.server->yaw_speed;
1069
1070         if (current == ideal)
1071                 return;
1072         move = ideal - current;
1073         if (ideal > current)
1074         {
1075                 if (move >= 180)
1076                         move = move - 360;
1077         }
1078         else
1079         {
1080                 if (move <= -180)
1081                         move = move + 360;
1082         }
1083         if (move > 0)
1084         {
1085                 if (move > speed)
1086                         move = speed;
1087         }
1088         else
1089         {
1090                 if (move < -speed)
1091                         move = -speed;
1092         }
1093
1094         ent->fields.server->angles[1] = ANGLEMOD (current + move);
1095 }
1096
1097 /*
1098 ==============
1099 PF_changepitch
1100 ==============
1101 */
1102 void PF_changepitch (void)
1103 {
1104         prvm_edict_t            *ent;
1105         float           ideal, current, move, speed;
1106         prvm_eval_t             *val;
1107
1108         ent = PRVM_G_EDICT(OFS_PARM0);
1109         if (ent == prog->edicts)
1110                 PF_WARNING("changepitch: can not modify world entity\n");
1111         if (ent->priv.server->free)
1112                 PF_WARNING("changepitch: can not modify free entity\n");
1113         current = ANGLEMOD( ent->fields.server->angles[0] );
1114         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1115                 ideal = val->_float;
1116         else
1117         {
1118                 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1119                 return;
1120         }
1121         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1122                 speed = val->_float;
1123         else
1124         {
1125                 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1126                 return;
1127         }
1128
1129         if (current == ideal)
1130                 return;
1131         move = ideal - current;
1132         if (ideal > current)
1133         {
1134                 if (move >= 180)
1135                         move = move - 360;
1136         }
1137         else
1138         {
1139                 if (move <= -180)
1140                         move = move + 360;
1141         }
1142         if (move > 0)
1143         {
1144                 if (move > speed)
1145                         move = speed;
1146         }
1147         else
1148         {
1149                 if (move < -speed)
1150                         move = -speed;
1151         }
1152
1153         ent->fields.server->angles[0] = ANGLEMOD (current + move);
1154 }
1155
1156 /*
1157 ===============================================================================
1158
1159 MESSAGE WRITING
1160
1161 ===============================================================================
1162 */
1163
1164 #define MSG_BROADCAST   0               // unreliable to all
1165 #define MSG_ONE                 1               // reliable to one (msg_entity)
1166 #define MSG_ALL                 2               // reliable to all
1167 #define MSG_INIT                3               // write to the init string
1168
1169 sizebuf_t *WriteDest (void)
1170 {
1171         int             entnum;
1172         int             dest;
1173         prvm_edict_t    *ent;
1174
1175         dest = PRVM_G_FLOAT(OFS_PARM0);
1176         switch (dest)
1177         {
1178         case MSG_BROADCAST:
1179                 return &sv.datagram;
1180
1181         case MSG_ONE:
1182                 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1183                 entnum = PRVM_NUM_FOR_EDICT(ent);
1184                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1185                         Host_Error("WriteDest: tried to write to non-client\n");
1186                 return &svs.clients[entnum-1].message;
1187
1188         case MSG_ALL:
1189                 return &sv.reliable_datagram;
1190
1191         case MSG_INIT:
1192                 return &sv.signon;
1193
1194         default:
1195                 Host_Error("WriteDest: bad destination");
1196                 break;
1197         }
1198
1199         return NULL;
1200 }
1201
1202 void PF_WriteByte (void)
1203 {
1204         MSG_WriteByte (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1205 }
1206
1207 void PF_WriteChar (void)
1208 {
1209         MSG_WriteChar (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1210 }
1211
1212 void PF_WriteShort (void)
1213 {
1214         MSG_WriteShort (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1215 }
1216
1217 void PF_WriteLong (void)
1218 {
1219         MSG_WriteLong (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1220 }
1221
1222 void PF_WriteAngle (void)
1223 {
1224         MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1225 }
1226
1227 void PF_WriteCoord (void)
1228 {
1229         MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1230 }
1231
1232 void PF_WriteString (void)
1233 {
1234         MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1235 }
1236
1237
1238 void PF_WriteEntity (void)
1239 {
1240         MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1241 }
1242
1243 //////////////////////////////////////////////////////////
1244
1245 void PF_makestatic (void)
1246 {
1247         prvm_edict_t *ent;
1248         int i, large;
1249
1250         ent = PRVM_G_EDICT(OFS_PARM0);
1251         if (ent == prog->edicts)
1252                 PF_WARNING("makestatic: can not modify world entity\n");
1253         if (ent->priv.server->free)
1254                 PF_WARNING("makestatic: can not modify free entity\n");
1255
1256         large = false;
1257         if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1258                 large = true;
1259
1260         if (large)
1261         {
1262                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1263                 MSG_WriteShort (&sv.signon, ent->fields.server->modelindex);
1264                 MSG_WriteShort (&sv.signon, ent->fields.server->frame);
1265         }
1266         else
1267         {
1268                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1269                 MSG_WriteByte (&sv.signon, ent->fields.server->modelindex);
1270                 MSG_WriteByte (&sv.signon, ent->fields.server->frame);
1271         }
1272
1273         MSG_WriteByte (&sv.signon, ent->fields.server->colormap);
1274         MSG_WriteByte (&sv.signon, ent->fields.server->skin);
1275         for (i=0 ; i<3 ; i++)
1276         {
1277                 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1278                 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1279         }
1280
1281 // throw the entity away now
1282         PRVM_ED_Free (ent);
1283 }
1284
1285 //=============================================================================
1286
1287 /*
1288 ==============
1289 PF_setspawnparms
1290 ==============
1291 */
1292 void PF_setspawnparms (void)
1293 {
1294         prvm_edict_t    *ent;
1295         int             i;
1296         client_t        *client;
1297
1298         ent = PRVM_G_EDICT(OFS_PARM0);
1299         i = PRVM_NUM_FOR_EDICT(ent);
1300         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1301         {
1302                 Con_Print("tried to setspawnparms on a non-client\n");
1303                 return;
1304         }
1305
1306         // copy spawn parms out of the client_t
1307         client = svs.clients + i-1;
1308         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1309                 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1310 }
1311
1312 /*
1313 =================
1314 PF_getlight
1315
1316 Returns a color vector indicating the lighting at the requested point.
1317
1318 (Internal Operation note: actually measures the light beneath the point, just like
1319                           the model lighting on the client)
1320
1321 getlight(vector)
1322 =================
1323 */
1324 void PF_getlight (void)
1325 {
1326         vec3_t ambientcolor, diffusecolor, diffusenormal;
1327         vec_t *p;
1328         p = PRVM_G_VECTOR(OFS_PARM0);
1329         VectorClear(ambientcolor);
1330         VectorClear(diffusecolor);
1331         VectorClear(diffusenormal);
1332         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1333                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1334         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1335 }
1336
1337 void PF_registercvar (void)
1338 {
1339         const char *name, *value;
1340         name = PRVM_G_STRING(OFS_PARM0);
1341         value = PRVM_G_STRING(OFS_PARM1);
1342         PRVM_G_FLOAT(OFS_RETURN) = 0;
1343
1344 // first check to see if it has already been defined
1345         if (Cvar_FindVar (name))
1346                 return;
1347
1348 // check for overlap with a command
1349         if (Cmd_Exists (name))
1350         {
1351                 Con_Printf("PF_registercvar: %s is a command\n", name);
1352                 return;
1353         }
1354
1355         Cvar_Get(name, value, 0);
1356
1357         PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1358 }
1359
1360 /*
1361 =================
1362 PF_copyentity
1363
1364 copies data from one entity to another
1365
1366 copyentity(src, dst)
1367 =================
1368 */
1369 void PF_copyentity (void)
1370 {
1371         prvm_edict_t *in, *out;
1372         in = PRVM_G_EDICT(OFS_PARM0);
1373         if (in == prog->edicts)
1374                 PF_WARNING("copyentity: can not read world entity\n");
1375         if (in->priv.server->free)
1376                 PF_WARNING("copyentity: can not read free entity\n");
1377         out = PRVM_G_EDICT(OFS_PARM1);
1378         if (out == prog->edicts)
1379                 PF_WARNING("copyentity: can not modify world entity\n");
1380         if (out->priv.server->free)
1381                 PF_WARNING("copyentity: can not modify free entity\n");
1382         memcpy(out->fields.server, in->fields.server, prog->progs->entityfields * 4);
1383 }
1384
1385
1386 /*
1387 =================
1388 PF_setcolor
1389
1390 sets the color of a client and broadcasts the update to all connected clients
1391
1392 setcolor(clientent, value)
1393 =================
1394 */
1395 void PF_setcolor (void)
1396 {
1397         client_t *client;
1398         int entnum, i;
1399         prvm_eval_t *val;
1400
1401         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1402         i = PRVM_G_FLOAT(OFS_PARM1);
1403
1404         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1405         {
1406                 Con_Print("tried to setcolor a non-client\n");
1407                 return;
1408         }
1409
1410         client = svs.clients + entnum-1;
1411         if (client->edict)
1412         {
1413                 if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1414                         val->_float = i;
1415                 client->edict->fields.server->team = (i & 15) + 1;
1416         }
1417         client->colors = i;
1418         if (client->old_colors != client->colors)
1419         {
1420                 client->old_colors = client->colors;
1421                 // send notification to all clients
1422                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1423                 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1424                 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1425         }
1426 }
1427
1428 /*
1429 =================
1430 PF_effect
1431
1432 effect(origin, modelname, startframe, framecount, framerate)
1433 =================
1434 */
1435 void PF_effect (void)
1436 {
1437         int i;
1438         const char *s;
1439         s = PRVM_G_STRING(OFS_PARM1);
1440         if (!s || !s[0])
1441                 PF_WARNING("effect: no model specified\n");
1442
1443         i = SV_ModelIndex(s, 1);
1444         if (!i)
1445                 PF_WARNING("effect: model not precached\n");
1446         SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
1447 }
1448
1449 void PF_te_blood (void)
1450 {
1451         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1452                 return;
1453         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1454         MSG_WriteByte(&sv.datagram, TE_BLOOD);
1455         // origin
1456         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1457         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1458         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1459         // velocity
1460         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1461         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1462         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1463         // count
1464         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1465 }
1466
1467 void PF_te_bloodshower (void)
1468 {
1469         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1470                 return;
1471         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1472         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1473         // min
1474         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1475         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1476         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1477         // max
1478         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1479         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1480         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1481         // speed
1482         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1483         // count
1484         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1485 }
1486
1487 void PF_te_explosionrgb (void)
1488 {
1489         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1490         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1491         // origin
1492         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1493         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1494         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1495         // color
1496         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1497         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1498         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1499 }
1500
1501 void PF_te_particlecube (void)
1502 {
1503         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1504                 return;
1505         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1506         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1507         // min
1508         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1509         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1510         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1511         // max
1512         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1513         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1514         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1515         // velocity
1516         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1517         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1518         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1519         // count
1520         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1521         // color
1522         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1523         // gravity true/false
1524         MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1525         // randomvel
1526         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1527 }
1528
1529 void PF_te_particlerain (void)
1530 {
1531         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1532                 return;
1533         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1534         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1535         // min
1536         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1537         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1538         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1539         // max
1540         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1541         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1542         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1543         // velocity
1544         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1545         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1546         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1547         // count
1548         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1549         // color
1550         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1551 }
1552
1553 void PF_te_particlesnow (void)
1554 {
1555         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1556                 return;
1557         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1558         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1559         // min
1560         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1561         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1562         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1563         // max
1564         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1565         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1566         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1567         // velocity
1568         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1569         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1570         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1571         // count
1572         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1573         // color
1574         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1575 }
1576
1577 void PF_te_spark (void)
1578 {
1579         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1580                 return;
1581         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1582         MSG_WriteByte(&sv.datagram, TE_SPARK);
1583         // origin
1584         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1585         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1586         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1587         // velocity
1588         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1589         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1590         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1591         // count
1592         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1593 }
1594
1595 void PF_te_gunshotquad (void)
1596 {
1597         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1598         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1599         // origin
1600         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1601         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1602         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1603 }
1604
1605 void PF_te_spikequad (void)
1606 {
1607         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1608         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1609         // origin
1610         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1611         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1612         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1613 }
1614
1615 void PF_te_superspikequad (void)
1616 {
1617         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1618         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1619         // origin
1620         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1621         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1622         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1623 }
1624
1625 void PF_te_explosionquad (void)
1626 {
1627         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1628         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1629         // origin
1630         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1631         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1632         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1633 }
1634
1635 void PF_te_smallflash (void)
1636 {
1637         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1638         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1639         // origin
1640         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1641         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1642         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1643 }
1644
1645 void PF_te_customflash (void)
1646 {
1647         if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
1648                 return;
1649         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1650         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
1651         // origin
1652         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1653         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1654         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1655         // radius
1656         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
1657         // lifetime
1658         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
1659         // color
1660         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
1661         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
1662         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
1663 }
1664
1665 void PF_te_gunshot (void)
1666 {
1667         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1668         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
1669         // origin
1670         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1671         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1672         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1673 }
1674
1675 void PF_te_spike (void)
1676 {
1677         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1678         MSG_WriteByte(&sv.datagram, TE_SPIKE);
1679         // origin
1680         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1681         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1682         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1683 }
1684
1685 void PF_te_superspike (void)
1686 {
1687         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1688         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
1689         // origin
1690         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1691         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1692         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1693 }
1694
1695 void PF_te_explosion (void)
1696 {
1697         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1698         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
1699         // origin
1700         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1701         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1702         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1703 }
1704
1705 void PF_te_tarexplosion (void)
1706 {
1707         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1708         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
1709         // origin
1710         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1711         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1712         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1713 }
1714
1715 void PF_te_wizspike (void)
1716 {
1717         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1718         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
1719         // origin
1720         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1721         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1722         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1723 }
1724
1725 void PF_te_knightspike (void)
1726 {
1727         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1728         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
1729         // origin
1730         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1731         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1732         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1733 }
1734
1735 void PF_te_lavasplash (void)
1736 {
1737         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1738         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
1739         // origin
1740         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1741         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1742         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1743 }
1744
1745 void PF_te_teleport (void)
1746 {
1747         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1748         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
1749         // origin
1750         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1751         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1752         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1753 }
1754
1755 void PF_te_explosion2 (void)
1756 {
1757         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1758         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
1759         // origin
1760         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1761         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1762         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1763         // color
1764         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM1));
1765         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
1766 }
1767
1768 void PF_te_lightning1 (void)
1769 {
1770         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1771         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
1772         // owner entity
1773         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1774         // start
1775         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1776         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1777         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1778         // end
1779         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1780         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1781         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1782 }
1783
1784 void PF_te_lightning2 (void)
1785 {
1786         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1787         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
1788         // owner entity
1789         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1790         // start
1791         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1792         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1793         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1794         // end
1795         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1796         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1797         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1798 }
1799
1800 void PF_te_lightning3 (void)
1801 {
1802         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1803         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
1804         // owner entity
1805         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1806         // start
1807         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1808         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1809         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1810         // end
1811         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1812         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1813         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1814 }
1815
1816 void PF_te_beam (void)
1817 {
1818         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1819         MSG_WriteByte(&sv.datagram, TE_BEAM);
1820         // owner entity
1821         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1822         // start
1823         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1824         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1825         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1826         // end
1827         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1828         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1829         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1830 }
1831
1832 void PF_te_plasmaburn (void)
1833 {
1834         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1835         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
1836         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1837         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1838         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1839 }
1840
1841 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
1842 {
1843         int i, j, k;
1844         float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
1845         const int *e;
1846         bestdist = 1000000000;
1847         VectorCopy(p, out);
1848         for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
1849         {
1850                 // clip original point to each triangle of the surface and find the
1851                 // triangle that is closest
1852                 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
1853                 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
1854                 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
1855                 TriangleNormal(v[0], v[1], v[2], facenormal);
1856                 VectorNormalize(facenormal);
1857                 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
1858                 VectorMA(p, offsetdist, facenormal, temp);
1859                 for (j = 0, k = 2;j < 3;k = j, j++)
1860                 {
1861                         VectorSubtract(v[k], v[j], edgenormal);
1862                         CrossProduct(edgenormal, facenormal, sidenormal);
1863                         VectorNormalize(sidenormal);
1864                         offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
1865                         if (offsetdist < 0)
1866                                 VectorMA(temp, offsetdist, sidenormal, temp);
1867                 }
1868                 dist = VectorDistance2(temp, p);
1869                 if (bestdist > dist)
1870                 {
1871                         bestdist = dist;
1872                         VectorCopy(temp, out);
1873                 }
1874         }
1875 }
1876
1877 static msurface_t *getsurface(prvm_edict_t *ed, int surfacenum)
1878 {
1879         int modelindex;
1880         model_t *model;
1881         if (!ed || ed->priv.server->free)
1882                 return NULL;
1883         modelindex = ed->fields.server->modelindex;
1884         if (modelindex < 1 || modelindex >= MAX_MODELS)
1885                 return NULL;
1886         model = sv.models[modelindex];
1887         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1888                 return NULL;
1889         return model->data_surfaces + surfacenum + model->firstmodelsurface;
1890 }
1891
1892
1893 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
1894 void PF_getsurfacenumpoints(void)
1895 {
1896         msurface_t *surface;
1897         // return 0 if no such surface
1898         if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1899         {
1900                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1901                 return;
1902         }
1903
1904         // note: this (incorrectly) assumes it is a simple polygon
1905         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1906 }
1907 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
1908 void PF_getsurfacepoint(void)
1909 {
1910         prvm_edict_t *ed;
1911         msurface_t *surface;
1912         int pointnum;
1913         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1914         ed = PRVM_G_EDICT(OFS_PARM0);
1915         if (!ed || ed->priv.server->free)
1916                 return;
1917         if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
1918                 return;
1919         // note: this (incorrectly) assumes it is a simple polygon
1920         pointnum = PRVM_G_FLOAT(OFS_PARM2);
1921         if (pointnum < 0 || pointnum >= surface->num_vertices)
1922                 return;
1923         // FIXME: implement rotation/scaling
1924         VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1925 }
1926 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
1927 void PF_getsurfacenormal(void)
1928 {
1929         msurface_t *surface;
1930         vec3_t normal;
1931         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1932         if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1933                 return;
1934         // FIXME: implement rotation/scaling
1935         // note: this (incorrectly) assumes it is a simple polygon
1936         // note: this only returns the first triangle, so it doesn't work very
1937         // well for curved surfaces or arbitrary meshes
1938         TriangleNormal((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 3, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
1939         VectorNormalize(normal);
1940         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1941 }
1942 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
1943 void PF_getsurfacetexture(void)
1944 {
1945         msurface_t *surface;
1946         PRVM_G_INT(OFS_RETURN) = 0;
1947         if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1948                 return;
1949         PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
1950 }
1951 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
1952 void PF_getsurfacenearpoint(void)
1953 {
1954         int surfacenum, best, modelindex;
1955         vec3_t clipped, p;
1956         vec_t dist, bestdist;
1957         prvm_edict_t *ed;
1958         model_t *model;
1959         msurface_t *surface;
1960         vec_t *point;
1961         PRVM_G_FLOAT(OFS_RETURN) = -1;
1962         ed = PRVM_G_EDICT(OFS_PARM0);
1963         point = PRVM_G_VECTOR(OFS_PARM1);
1964
1965         if (!ed || ed->priv.server->free)
1966                 return;
1967         modelindex = ed->fields.server->modelindex;
1968         if (modelindex < 1 || modelindex >= MAX_MODELS)
1969                 return;
1970         model = sv.models[modelindex];
1971         if (!model->num_surfaces)
1972                 return;
1973
1974         // FIXME: implement rotation/scaling
1975         VectorSubtract(point, ed->fields.server->origin, p);
1976         best = -1;
1977         bestdist = 1000000000;
1978         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1979         {
1980                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1981                 // first see if the nearest point on the surface's box is closer than the previous match
1982                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1983                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1984                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1985                 dist = VectorLength2(clipped);
1986                 if (dist < bestdist)
1987                 {
1988                         // it is, check the nearest point on the actual geometry
1989                         clippointtosurface(surface, p, clipped);
1990                         VectorSubtract(clipped, p, clipped);
1991                         dist += VectorLength2(clipped);
1992                         if (dist < bestdist)
1993                         {
1994                                 // that's closer too, store it as the best match
1995                                 best = surfacenum;
1996                                 bestdist = dist;
1997                         }
1998                 }
1999         }
2000         PRVM_G_FLOAT(OFS_RETURN) = best;
2001 }
2002 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2003 void PF_getsurfaceclippedpoint(void)
2004 {
2005         prvm_edict_t *ed;
2006         msurface_t *surface;
2007         vec3_t p, out;
2008         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2009         ed = PRVM_G_EDICT(OFS_PARM0);
2010         if (!ed || ed->priv.server->free)
2011                 return;
2012         if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
2013                 return;
2014         // FIXME: implement rotation/scaling
2015         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2016         clippointtosurface(surface, p, out);
2017         // FIXME: implement rotation/scaling
2018         VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2019 }
2020
2021 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2022 //this function originally written by KrimZon, made shorter by LordHavoc
2023 void PF_clientcommand (void)
2024 {
2025         client_t *temp_client;
2026         int i;
2027
2028         //find client for this entity
2029         i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2030         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2031         {
2032                 Con_Print("PF_clientcommand: entity is not a client\n");
2033                 return;
2034         }
2035
2036         temp_client = host_client;
2037         host_client = svs.clients + i;
2038         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2039         host_client = temp_client;
2040 }
2041
2042 //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)
2043 void PF_setattachment (void)
2044 {
2045         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2046         prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2047         const char *tagname = PRVM_G_STRING(OFS_PARM2);
2048         prvm_eval_t *v;
2049         int modelindex;
2050         model_t *model;
2051
2052         if (e == prog->edicts)
2053                 PF_WARNING("setattachment: can not modify world entity\n");
2054         if (e->priv.server->free)
2055                 PF_WARNING("setattachment: can not modify free entity\n");
2056
2057         if (tagentity == NULL)
2058                 tagentity = prog->edicts;
2059
2060         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
2061         if (v)
2062                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2063
2064         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
2065         if (v)
2066                 v->_float = 0;
2067         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2068         {
2069                 modelindex = (int)tagentity->fields.server->modelindex;
2070                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
2071                 {
2072                         v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->fields.server->skin, tagname);
2073                         if (v->_float == 0)
2074                                 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", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name);
2075                 }
2076                 else
2077                         Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity));
2078         }
2079 }
2080
2081 /////////////////////////////////////////
2082 // DP_MD3_TAGINFO extension coded by VorteX
2083
2084 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2085 {
2086         int i;
2087         model_t *model;
2088
2089         i = e->fields.server->modelindex;
2090         if (i < 1 || i >= MAX_MODELS)
2091                 return -1;
2092         model = sv.models[i];
2093
2094         return Mod_Alias_GetTagIndexForName(model, e->fields.server->skin, tagname);
2095 };
2096
2097 // Warnings/errors code:
2098 // 0 - normal (everything all-right)
2099 // 1 - world entity
2100 // 2 - free entity
2101 // 3 - null or non-precached model
2102 // 4 - no tags with requested index
2103 // 5 - runaway loop at attachment chain
2104 extern cvar_t cl_bob;
2105 extern cvar_t cl_bobcycle;
2106 extern cvar_t cl_bobup;
2107 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2108 {
2109         prvm_eval_t *val;
2110         int modelindex, reqframe, attachloop;
2111         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2112         prvm_edict_t *attachent;
2113         model_t *model;
2114
2115         Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
2116
2117         if (ent == prog->edicts)
2118                 return 1;
2119         if (ent->priv.server->free)
2120                 return 2;
2121
2122         modelindex = (int)ent->fields.server->modelindex;
2123         if (modelindex <= 0 || modelindex > MAX_MODELS)
2124                 return 3;
2125
2126         model = sv.models[modelindex];
2127
2128         if (ent->fields.server->frame >= 0 && ent->fields.server->frame < model->numframes && model->animscenes)
2129                 reqframe = model->animscenes[(int)ent->fields.server->frame].firstframe;
2130         else
2131                 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2132
2133         // get initial tag matrix
2134         if (tagindex)
2135         {
2136                 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2137                 if (ret)
2138                         return ret;
2139         }
2140         else
2141                 Matrix4x4_CreateIdentity(&tagmatrix);
2142
2143         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
2144         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2145                 attachloop = 0;
2146                 do
2147                 {
2148                         attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2149                         val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index);
2150                         if (val->_float >= 1 && attachent->fields.server->modelindex >= 1 && attachent->fields.server->modelindex < MAX_MODELS && (model = sv.models[(int)attachent->fields.server->modelindex]) && model->animscenes && attachent->fields.server->frame >= 0 && attachent->fields.server->frame < model->numframes)
2151                                 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.server->frame].firstframe, val->_float - 1, &attachmatrix);
2152                         else
2153                                 Matrix4x4_CreateIdentity(&attachmatrix);
2154
2155                         // apply transformation by child entity matrix
2156                         val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
2157                         if (val->_float == 0)
2158                                 val->_float = 1;
2159                         Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], -ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], val->_float);
2160                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2161                         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]);
2162                         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]);
2163                         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]);
2164                         Matrix4x4_Copy(&tagmatrix, out);
2165
2166                         // finally transformate by matrix of tag on parent entity
2167                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2168                         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];
2169                         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];
2170                         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];
2171                         Matrix4x4_Copy(&tagmatrix, out);
2172
2173                         ent = attachent;
2174                         attachloop += 1;
2175                         if (attachloop > 255) // prevent runaway looping
2176                                 return 5;
2177                 }
2178                 while ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
2179         }
2180
2181         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2182         val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
2183         if (val->_float == 0)
2184                 val->_float = 1;
2185         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2186         Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], -ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], val->_float);
2187         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2188         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]);
2189         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]);
2190         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]);
2191
2192         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
2193         {// RENDER_VIEWMODEL magic
2194                 Matrix4x4_Copy(&tagmatrix, out);
2195                 ent = PRVM_EDICT_NUM(val->edict);
2196
2197                 val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
2198                 if (val->_float == 0)
2199                         val->_float = 1;
2200
2201                 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + ent->fields.server->view_ofs[2], ent->fields.server->v_angle[0], ent->fields.server->v_angle[1], ent->fields.server->v_angle[2], val->_float);
2202                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2203                 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]);
2204                 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]);
2205                 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]);
2206
2207                 /*
2208                 // Cl_bob, ported from rendering code
2209                 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2210                 {
2211                         double bob, cycle;
2212                         // LordHavoc: this code is *weird*, but not replacable (I think it
2213                         // should be done in QC on the server, but oh well, quake is quake)
2214                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2215                         // degrees (which allows lengthening or squishing the peak or valley)
2216                         cycle = sv.time/cl_bobcycle.value;
2217                         cycle -= (int)cycle;
2218                         if (cycle < cl_bobup.value)
2219                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2220                         else
2221                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2222                         // bob is proportional to velocity in the xy plane
2223                         // (don't count Z, or jumping messes it up)
2224                         bob = sqrt(ent->fields.server->velocity[0]*ent->fields.server->velocity[0] + ent->fields.server->velocity[1]*ent->fields.server->velocity[1])*cl_bob.value;
2225                         bob = bob*0.3 + bob*0.7*cycle;
2226                         out->m[2][3] += bound(-7, bob, 4);
2227                 }
2228                 */
2229         }
2230         return 0;
2231 }
2232
2233 //float(entity ent, string tagname) gettagindex;
2234
2235 void PF_gettagindex (void)
2236 {
2237         prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
2238         const char *tag_name = PRVM_G_STRING(OFS_PARM1);
2239         int modelindex, tag_index;
2240
2241         if (ent == prog->edicts)
2242                 PF_WARNING("gettagindex: can't affect world entity\n");
2243         if (ent->priv.server->free)
2244                 PF_WARNING("gettagindex: can't affect free entity\n");
2245
2246         modelindex = (int)ent->fields.server->modelindex;
2247         tag_index = 0;
2248         if (modelindex <= 0 || modelindex > MAX_MODELS)
2249                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2250         else
2251         {
2252                 tag_index = SV_GetTagIndex(ent, tag_name);
2253                 if (tag_index == 0)
2254                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2255         }
2256         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2257 };
2258
2259 //vector(entity ent, float tagindex) gettaginfo;
2260 void PF_gettaginfo (void)
2261 {
2262         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2263         int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2264         matrix4x4_t tag_matrix;
2265         int returncode;
2266
2267         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2268         Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2269
2270         switch(returncode)
2271         {
2272                 case 1:
2273                         PF_WARNING("gettagindex: can't affect world entity\n");
2274                         break;
2275                 case 2:
2276                         PF_WARNING("gettagindex: can't affect free entity\n");
2277                         break;
2278                 case 3:
2279                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2280                         break;
2281                 case 4:
2282                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2283                         break;
2284                 case 5:
2285                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2286                         break;
2287         }
2288 }
2289
2290 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2291 void PF_dropclient (void)
2292 {
2293         int clientnum;
2294         client_t *oldhostclient;
2295         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2296         if (clientnum < 0 || clientnum >= svs.maxclients)
2297                 PF_WARNING("dropclient: not a client\n");
2298         if (!svs.clients[clientnum].active)
2299                 PF_WARNING("dropclient: that client slot is not connected\n");
2300         oldhostclient = host_client;
2301         host_client = svs.clients + clientnum;
2302         SV_DropClient(false);
2303         host_client = oldhostclient;
2304 }
2305
2306 //entity() spawnclient (DP_SV_BOTCLIENT)
2307 void PF_spawnclient (void)
2308 {
2309         int i;
2310         prvm_edict_t    *ed;
2311         prog->xfunction->builtinsprofile += 2;
2312         ed = prog->edicts;
2313         for (i = 0;i < svs.maxclients;i++)
2314         {
2315                 if (!svs.clients[i].active)
2316                 {
2317                         prog->xfunction->builtinsprofile += 100;
2318                         SV_ConnectClient (i, NULL);
2319                         ed = PRVM_EDICT_NUM(i + 1);
2320                         break;
2321                 }
2322         }
2323         VM_RETURN_EDICT(ed);
2324 }
2325
2326 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2327 void PF_clienttype (void)
2328 {
2329         int clientnum;
2330         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2331         if (clientnum < 0 || clientnum >= svs.maxclients)
2332                 PRVM_G_FLOAT(OFS_RETURN) = 3;
2333         else if (!svs.clients[clientnum].active)
2334                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2335         else if (svs.clients[clientnum].netconnection)
2336                 PRVM_G_FLOAT(OFS_RETURN) = 1;
2337         else
2338                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2339 }
2340
2341 prvm_builtin_t vm_sv_builtins[] = {
2342 NULL,                                           // #0
2343 PF_makevectors,                         // #1 void(entity e) makevectors
2344 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
2345 PF_setmodel,                            // #3 void(entity e, string m) setmodel
2346 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
2347 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
2348 VM_break,                                       // #6 void() break
2349 VM_random,                                      // #7 float() random
2350 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
2351 VM_normalize,                           // #9 vector(vector v) normalize
2352 VM_error,                                       // #10 void(string e) error
2353 VM_objerror,                            // #11 void(string e) objerror
2354 VM_vlen,                                        // #12 float(vector v) vlen
2355 VM_vectoyaw,                            // #13 float(vector v) vectoyaw
2356 VM_spawn,                                       // #14 entity() spawn
2357 VM_remove,                                      // #15 void(entity e) remove
2358 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
2359 PF_checkclient,                         // #17 entity() clientlist
2360 VM_find,                                        // #18 entity(entity start, .string fld, string match) find
2361 PF_precache_sound,                      // #19 void(string s) precache_sound
2362 PF_precache_model,                      // #20 void(string s) precache_model
2363 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
2364 PF_findradius,                          // #22 entity(vector org, float rad) findradius
2365 VM_bprint,                                      // #23 void(string s) bprint
2366 PF_sprint,                                      // #24 void(entity client, string s) sprint
2367 VM_dprint,                                      // #25 void(string s) dprint
2368 VM_ftos,                                        // #26 void(string s) ftos
2369 VM_vtos,                                        // #27 void(string s) vtos
2370 VM_coredump,                            // #28 void() coredump
2371 VM_traceon,                                     // #29 void() traceon
2372 VM_traceoff,                            // #30 void() traceoff
2373 VM_eprint,                                      // #31 void(entity e) eprint
2374 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
2375 NULL,                                           // #33
2376 PF_droptofloor,                         // #34 float() droptofloor
2377 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
2378 VM_rint,                                        // #36 float(float v) rint
2379 VM_floor,                                       // #37 float(float v) floor
2380 VM_ceil,                                        // #38 float(float v) ceil
2381 NULL,                                           // #39
2382 PF_checkbottom,                         // #40 float(entity e) checkbottom
2383 PF_pointcontents,                       // #41 float(vector v) pointcontents
2384 NULL,                                           // #42
2385 VM_fabs,                                        // #43 float(float f) fabs
2386 PF_aim,                                         // #44 vector(entity e, float speed) aim
2387 VM_cvar,                                        // #45 float(string s) cvar
2388 VM_localcmd,                            // #46 void(string s) localcmd
2389 VM_nextent,                                     // #47 entity(entity e) nextent
2390 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
2391 PF_changeyaw,                           // #49 void() ChangeYaw
2392 NULL,                                           // #50
2393 VM_vectoangles,                         // #51 vector(vector v) vectoangles
2394 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
2395 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
2396 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
2397 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
2398 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
2399 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
2400 PF_WriteString,                         // #58 void(float to, string s) WriteString
2401 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
2402 VM_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2403 VM_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2404 VM_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2405 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2406 PF_tracetoss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2407 VM_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
2408 NULL,                                           // #66
2409 SV_MoveToGoal,                          // #67 void(float step) movetogoal
2410 PF_precache_file,                       // #68 string(string s) precache_file
2411 PF_makestatic,                          // #69 void(entity e) makestatic
2412 VM_changelevel,                         // #70 void(string s) changelevel
2413 NULL,                                           // #71
2414 VM_cvar_set,                            // #72 void(string var, string val) cvar_set
2415 PF_centerprint,                         // #73 void(entity client, strings) centerprint
2416 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2417 PF_precache_model,                      // #75 string(string s) precache_model2
2418 PF_precache_sound,                      // #76 string(string s) precache_sound2
2419 PF_precache_file,                       // #77 string(string s) precache_file2
2420 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
2421 NULL,                                           // #79
2422 NULL,                                           // #80
2423 VM_stof,                                        // #81 float(string s) stof (FRIK_FILE)
2424 NULL,                                           // #82
2425 NULL,                                           // #83
2426 NULL,                                           // #84
2427 NULL,                                           // #85
2428 NULL,                                           // #86
2429 NULL,                                           // #87
2430 NULL,                                           // #88
2431 NULL,                                           // #89
2432 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2433 VM_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
2434 PF_getlight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2435 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2436 VM_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2437 VM_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2438 VM_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2439 VM_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2440 VM_findfloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2441 VM_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
2442 NULL,                                           // #100
2443 NULL,                                           // #101
2444 NULL,                                           // #102
2445 NULL,                                           // #103
2446 NULL,                                           // #104
2447 NULL,                                           // #105
2448 NULL,                                           // #106
2449 NULL,                                           // #107
2450 NULL,                                           // #108
2451 NULL,                                           // #109
2452 VM_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
2453 VM_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
2454 VM_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
2455 VM_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2456 VM_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
2457 VM_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
2458 VM_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
2459 VM_stov,                                        // #117 vector(string) stov (FRIK_FILE)
2460 VM_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
2461 VM_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
2462 e10, e10, e10, e10, e10, e10, e10, e10,         // #120-199
2463 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10,       // #200-299
2464 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10,       // #300-399
2465 VM_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
2466 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
2467 VM_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
2468 VM_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
2469 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2470 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2471 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2472 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2473 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2474 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2475 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2476 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
2477 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2478 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2479 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2480 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2481 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2482 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2483 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2484 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2485 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2486 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2487 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2488 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2489 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2490 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2491 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2492 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2493 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
2494 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
2495 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
2496 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
2497 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
2498 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
2499 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
2500 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
2501 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
2502 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
2503 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
2504 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
2505 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
2506 VM_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
2507 VM_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
2508 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
2509 VM_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
2510 VM_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
2511 VM_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
2512 VM_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
2513 VM_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
2514 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
2515 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
2516 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2517 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2518 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
2519 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
2520 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
2521 NULL,                                           // #456
2522 NULL,                                           // #457
2523 NULL,                                           // #458
2524 NULL,                                           // #459
2525 e10, e10, e10, e10                      // #460-499 (LordHavoc)
2526 };
2527
2528 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2529
2530 void VM_SV_Cmd_Init(void)
2531 {
2532         VM_Cmd_Init();
2533 }
2534
2535 void VM_SV_Cmd_Reset(void)
2536 {
2537         VM_Cmd_Reset();
2538 }
2539