]> icculus.org git repositories - divverent/darkplaces.git/blob - svvm_cmds.c
allow multiple lightning beams owned by world
[divverent/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                 {
1186                         Con_Printf ("WriteDest: tried to write to non-client\n");
1187                         return &sv.reliable_datagram;
1188                 }
1189                 else
1190                         return &svs.clients[entnum-1].message;
1191
1192         default:
1193                 Con_Printf ("WriteDest: bad destination");
1194         case MSG_ALL:
1195                 return &sv.reliable_datagram;
1196
1197         case MSG_INIT:
1198                 return &sv.signon;
1199         }
1200
1201         return NULL;
1202 }
1203
1204 void PF_WriteByte (void)
1205 {
1206         MSG_WriteByte (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1207 }
1208
1209 void PF_WriteChar (void)
1210 {
1211         MSG_WriteChar (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1212 }
1213
1214 void PF_WriteShort (void)
1215 {
1216         MSG_WriteShort (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1217 }
1218
1219 void PF_WriteLong (void)
1220 {
1221         MSG_WriteLong (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1222 }
1223
1224 void PF_WriteAngle (void)
1225 {
1226         MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1227 }
1228
1229 void PF_WriteCoord (void)
1230 {
1231         MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1232 }
1233
1234 void PF_WriteString (void)
1235 {
1236         MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1237 }
1238
1239
1240 void PF_WriteEntity (void)
1241 {
1242         MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1243 }
1244
1245 //////////////////////////////////////////////////////////
1246
1247 void PF_makestatic (void)
1248 {
1249         prvm_edict_t *ent;
1250         int i, large;
1251
1252         ent = PRVM_G_EDICT(OFS_PARM0);
1253         if (ent == prog->edicts)
1254                 PF_WARNING("makestatic: can not modify world entity\n");
1255         if (ent->priv.server->free)
1256                 PF_WARNING("makestatic: can not modify free entity\n");
1257
1258         large = false;
1259         if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1260                 large = true;
1261
1262         if (large)
1263         {
1264                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1265                 MSG_WriteShort (&sv.signon, ent->fields.server->modelindex);
1266                 MSG_WriteShort (&sv.signon, ent->fields.server->frame);
1267         }
1268         else
1269         {
1270                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1271                 MSG_WriteByte (&sv.signon, ent->fields.server->modelindex);
1272                 MSG_WriteByte (&sv.signon, ent->fields.server->frame);
1273         }
1274
1275         MSG_WriteByte (&sv.signon, ent->fields.server->colormap);
1276         MSG_WriteByte (&sv.signon, ent->fields.server->skin);
1277         for (i=0 ; i<3 ; i++)
1278         {
1279                 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1280                 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1281         }
1282
1283 // throw the entity away now
1284         PRVM_ED_Free (ent);
1285 }
1286
1287 //=============================================================================
1288
1289 /*
1290 ==============
1291 PF_setspawnparms
1292 ==============
1293 */
1294 void PF_setspawnparms (void)
1295 {
1296         prvm_edict_t    *ent;
1297         int             i;
1298         client_t        *client;
1299
1300         ent = PRVM_G_EDICT(OFS_PARM0);
1301         i = PRVM_NUM_FOR_EDICT(ent);
1302         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1303         {
1304                 Con_Print("tried to setspawnparms on a non-client\n");
1305                 return;
1306         }
1307
1308         // copy spawn parms out of the client_t
1309         client = svs.clients + i-1;
1310         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1311                 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1312 }
1313
1314 /*
1315 =================
1316 PF_getlight
1317
1318 Returns a color vector indicating the lighting at the requested point.
1319
1320 (Internal Operation note: actually measures the light beneath the point, just like
1321                           the model lighting on the client)
1322
1323 getlight(vector)
1324 =================
1325 */
1326 void PF_getlight (void)
1327 {
1328         vec3_t ambientcolor, diffusecolor, diffusenormal;
1329         vec_t *p;
1330         p = PRVM_G_VECTOR(OFS_PARM0);
1331         VectorClear(ambientcolor);
1332         VectorClear(diffusecolor);
1333         VectorClear(diffusenormal);
1334         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1335                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1336         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1337 }
1338
1339 void PF_registercvar (void)
1340 {
1341         const char *name, *value;
1342         name = PRVM_G_STRING(OFS_PARM0);
1343         value = PRVM_G_STRING(OFS_PARM1);
1344         PRVM_G_FLOAT(OFS_RETURN) = 0;
1345
1346 // first check to see if it has already been defined
1347         if (Cvar_FindVar (name))
1348                 return;
1349
1350 // check for overlap with a command
1351         if (Cmd_Exists (name))
1352         {
1353                 Con_Printf("PF_registercvar: %s is a command\n", name);
1354                 return;
1355         }
1356
1357         Cvar_Get(name, value, 0);
1358
1359         PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1360 }
1361
1362 /*
1363 =================
1364 PF_copyentity
1365
1366 copies data from one entity to another
1367
1368 copyentity(src, dst)
1369 =================
1370 */
1371 void PF_copyentity (void)
1372 {
1373         prvm_edict_t *in, *out;
1374         in = PRVM_G_EDICT(OFS_PARM0);
1375         if (in == prog->edicts)
1376                 PF_WARNING("copyentity: can not read world entity\n");
1377         if (in->priv.server->free)
1378                 PF_WARNING("copyentity: can not read free entity\n");
1379         out = PRVM_G_EDICT(OFS_PARM1);
1380         if (out == prog->edicts)
1381                 PF_WARNING("copyentity: can not modify world entity\n");
1382         if (out->priv.server->free)
1383                 PF_WARNING("copyentity: can not modify free entity\n");
1384         memcpy(out->fields.server, in->fields.server, prog->progs->entityfields * 4);
1385 }
1386
1387
1388 /*
1389 =================
1390 PF_setcolor
1391
1392 sets the color of a client and broadcasts the update to all connected clients
1393
1394 setcolor(clientent, value)
1395 =================
1396 */
1397 void PF_setcolor (void)
1398 {
1399         client_t *client;
1400         int entnum, i;
1401         prvm_eval_t *val;
1402
1403         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1404         i = PRVM_G_FLOAT(OFS_PARM1);
1405
1406         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1407         {
1408                 Con_Print("tried to setcolor a non-client\n");
1409                 return;
1410         }
1411
1412         client = svs.clients + entnum-1;
1413         if (client->edict)
1414         {
1415                 if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1416                         val->_float = i;
1417                 client->edict->fields.server->team = (i & 15) + 1;
1418         }
1419         client->colors = i;
1420         if (client->old_colors != client->colors)
1421         {
1422                 client->old_colors = client->colors;
1423                 // send notification to all clients
1424                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1425                 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1426                 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1427         }
1428 }
1429
1430 /*
1431 =================
1432 PF_effect
1433
1434 effect(origin, modelname, startframe, framecount, framerate)
1435 =================
1436 */
1437 void PF_effect (void)
1438 {
1439         int i;
1440         const char *s;
1441         s = PRVM_G_STRING(OFS_PARM1);
1442         if (!s || !s[0])
1443                 PF_WARNING("effect: no model specified\n");
1444
1445         i = SV_ModelIndex(s, 1);
1446         if (!i)
1447                 PF_WARNING("effect: model not precached\n");
1448         SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
1449 }
1450
1451 void PF_te_blood (void)
1452 {
1453         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1454                 return;
1455         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1456         MSG_WriteByte(&sv.datagram, TE_BLOOD);
1457         // origin
1458         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1459         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1460         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1461         // velocity
1462         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1463         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1464         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1465         // count
1466         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1467 }
1468
1469 void PF_te_bloodshower (void)
1470 {
1471         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1472                 return;
1473         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1474         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1475         // min
1476         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1477         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1478         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1479         // max
1480         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1481         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1482         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1483         // speed
1484         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1485         // count
1486         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1487 }
1488
1489 void PF_te_explosionrgb (void)
1490 {
1491         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1492         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1493         // origin
1494         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1495         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1496         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1497         // color
1498         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1499         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1500         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1501 }
1502
1503 void PF_te_particlecube (void)
1504 {
1505         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1506                 return;
1507         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1508         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1509         // min
1510         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1511         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1512         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1513         // max
1514         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1515         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1516         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1517         // velocity
1518         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1519         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1520         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1521         // count
1522         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1523         // color
1524         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1525         // gravity true/false
1526         MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1527         // randomvel
1528         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1529 }
1530
1531 void PF_te_particlerain (void)
1532 {
1533         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1534                 return;
1535         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1536         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1537         // min
1538         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1539         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1540         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1541         // max
1542         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1543         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1544         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1545         // velocity
1546         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1547         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1548         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1549         // count
1550         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1551         // color
1552         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1553 }
1554
1555 void PF_te_particlesnow (void)
1556 {
1557         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1558                 return;
1559         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1560         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1561         // min
1562         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1563         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1564         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1565         // max
1566         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1567         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1568         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1569         // velocity
1570         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1571         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1572         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1573         // count
1574         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1575         // color
1576         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1577 }
1578
1579 void PF_te_spark (void)
1580 {
1581         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1582                 return;
1583         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1584         MSG_WriteByte(&sv.datagram, TE_SPARK);
1585         // origin
1586         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1587         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1588         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1589         // velocity
1590         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1591         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1592         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1593         // count
1594         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1595 }
1596
1597 void PF_te_gunshotquad (void)
1598 {
1599         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1600         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1601         // origin
1602         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1603         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1604         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1605 }
1606
1607 void PF_te_spikequad (void)
1608 {
1609         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1610         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1611         // origin
1612         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1613         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1614         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1615 }
1616
1617 void PF_te_superspikequad (void)
1618 {
1619         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1620         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1621         // origin
1622         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1623         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1624         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1625 }
1626
1627 void PF_te_explosionquad (void)
1628 {
1629         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1630         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1631         // origin
1632         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1633         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1634         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1635 }
1636
1637 void PF_te_smallflash (void)
1638 {
1639         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1640         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1641         // origin
1642         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1643         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1644         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1645 }
1646
1647 void PF_te_customflash (void)
1648 {
1649         if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
1650                 return;
1651         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1652         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
1653         // origin
1654         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1655         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1656         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1657         // radius
1658         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
1659         // lifetime
1660         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
1661         // color
1662         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
1663         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
1664         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
1665 }
1666
1667 void PF_te_gunshot (void)
1668 {
1669         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1670         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
1671         // origin
1672         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1673         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1674         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1675 }
1676
1677 void PF_te_spike (void)
1678 {
1679         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1680         MSG_WriteByte(&sv.datagram, TE_SPIKE);
1681         // origin
1682         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1683         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1684         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1685 }
1686
1687 void PF_te_superspike (void)
1688 {
1689         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1690         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
1691         // origin
1692         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1693         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1694         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1695 }
1696
1697 void PF_te_explosion (void)
1698 {
1699         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1700         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
1701         // origin
1702         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1703         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1704         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1705 }
1706
1707 void PF_te_tarexplosion (void)
1708 {
1709         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1710         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
1711         // origin
1712         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1713         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1714         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1715 }
1716
1717 void PF_te_wizspike (void)
1718 {
1719         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1720         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
1721         // origin
1722         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1723         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1724         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1725 }
1726
1727 void PF_te_knightspike (void)
1728 {
1729         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1730         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
1731         // origin
1732         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1733         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1734         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1735 }
1736
1737 void PF_te_lavasplash (void)
1738 {
1739         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1740         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
1741         // origin
1742         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1743         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1744         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1745 }
1746
1747 void PF_te_teleport (void)
1748 {
1749         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1750         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
1751         // origin
1752         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1753         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1754         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1755 }
1756
1757 void PF_te_explosion2 (void)
1758 {
1759         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1760         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
1761         // origin
1762         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1763         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1764         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1765         // color
1766         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM1));
1767         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
1768 }
1769
1770 void PF_te_lightning1 (void)
1771 {
1772         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1773         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
1774         // owner entity
1775         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1776         // start
1777         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1778         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1779         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1780         // end
1781         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1782         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1783         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1784 }
1785
1786 void PF_te_lightning2 (void)
1787 {
1788         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1789         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
1790         // owner entity
1791         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1792         // start
1793         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1794         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1795         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1796         // end
1797         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1798         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1799         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1800 }
1801
1802 void PF_te_lightning3 (void)
1803 {
1804         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1805         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
1806         // owner entity
1807         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1808         // start
1809         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1810         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1811         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1812         // end
1813         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1814         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1815         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1816 }
1817
1818 void PF_te_beam (void)
1819 {
1820         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1821         MSG_WriteByte(&sv.datagram, TE_BEAM);
1822         // owner entity
1823         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1824         // start
1825         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1826         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1827         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1828         // end
1829         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1830         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1831         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1832 }
1833
1834 void PF_te_plasmaburn (void)
1835 {
1836         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1837         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
1838         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1839         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1840         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1841 }
1842
1843 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
1844 {
1845         int i, j, k;
1846         float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
1847         const int *e;
1848         bestdist = 1000000000;
1849         VectorCopy(p, out);
1850         for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
1851         {
1852                 // clip original point to each triangle of the surface and find the
1853                 // triangle that is closest
1854                 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
1855                 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
1856                 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
1857                 TriangleNormal(v[0], v[1], v[2], facenormal);
1858                 VectorNormalize(facenormal);
1859                 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
1860                 VectorMA(p, offsetdist, facenormal, temp);
1861                 for (j = 0, k = 2;j < 3;k = j, j++)
1862                 {
1863                         VectorSubtract(v[k], v[j], edgenormal);
1864                         CrossProduct(edgenormal, facenormal, sidenormal);
1865                         VectorNormalize(sidenormal);
1866                         offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
1867                         if (offsetdist < 0)
1868                                 VectorMA(temp, offsetdist, sidenormal, temp);
1869                 }
1870                 dist = VectorDistance2(temp, p);
1871                 if (bestdist > dist)
1872                 {
1873                         bestdist = dist;
1874                         VectorCopy(temp, out);
1875                 }
1876         }
1877 }
1878
1879 static msurface_t *getsurface(prvm_edict_t *ed, int surfacenum)
1880 {
1881         int modelindex;
1882         model_t *model;
1883         if (!ed || ed->priv.server->free)
1884                 return NULL;
1885         modelindex = ed->fields.server->modelindex;
1886         if (modelindex < 1 || modelindex >= MAX_MODELS)
1887                 return NULL;
1888         model = sv.models[modelindex];
1889         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1890                 return NULL;
1891         return model->data_surfaces + surfacenum + model->firstmodelsurface;
1892 }
1893
1894
1895 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
1896 void PF_getsurfacenumpoints(void)
1897 {
1898         msurface_t *surface;
1899         // return 0 if no such surface
1900         if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1901         {
1902                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1903                 return;
1904         }
1905
1906         // note: this (incorrectly) assumes it is a simple polygon
1907         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1908 }
1909 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
1910 void PF_getsurfacepoint(void)
1911 {
1912         prvm_edict_t *ed;
1913         msurface_t *surface;
1914         int pointnum;
1915         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1916         ed = PRVM_G_EDICT(OFS_PARM0);
1917         if (!ed || ed->priv.server->free)
1918                 return;
1919         if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
1920                 return;
1921         // note: this (incorrectly) assumes it is a simple polygon
1922         pointnum = PRVM_G_FLOAT(OFS_PARM2);
1923         if (pointnum < 0 || pointnum >= surface->num_vertices)
1924                 return;
1925         // FIXME: implement rotation/scaling
1926         VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1927 }
1928 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
1929 void PF_getsurfacenormal(void)
1930 {
1931         msurface_t *surface;
1932         vec3_t normal;
1933         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1934         if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1935                 return;
1936         // FIXME: implement rotation/scaling
1937         // note: this (incorrectly) assumes it is a simple polygon
1938         // note: this only returns the first triangle, so it doesn't work very
1939         // well for curved surfaces or arbitrary meshes
1940         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);
1941         VectorNormalize(normal);
1942         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1943 }
1944 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
1945 void PF_getsurfacetexture(void)
1946 {
1947         msurface_t *surface;
1948         PRVM_G_INT(OFS_RETURN) = 0;
1949         if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1950                 return;
1951         PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
1952 }
1953 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
1954 void PF_getsurfacenearpoint(void)
1955 {
1956         int surfacenum, best, modelindex;
1957         vec3_t clipped, p;
1958         vec_t dist, bestdist;
1959         prvm_edict_t *ed;
1960         model_t *model;
1961         msurface_t *surface;
1962         vec_t *point;
1963         PRVM_G_FLOAT(OFS_RETURN) = -1;
1964         ed = PRVM_G_EDICT(OFS_PARM0);
1965         point = PRVM_G_VECTOR(OFS_PARM1);
1966
1967         if (!ed || ed->priv.server->free)
1968                 return;
1969         modelindex = ed->fields.server->modelindex;
1970         if (modelindex < 1 || modelindex >= MAX_MODELS)
1971                 return;
1972         model = sv.models[modelindex];
1973         if (!model->num_surfaces)
1974                 return;
1975
1976         // FIXME: implement rotation/scaling
1977         VectorSubtract(point, ed->fields.server->origin, p);
1978         best = -1;
1979         bestdist = 1000000000;
1980         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1981         {
1982                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1983                 // first see if the nearest point on the surface's box is closer than the previous match
1984                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1985                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1986                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1987                 dist = VectorLength2(clipped);
1988                 if (dist < bestdist)
1989                 {
1990                         // it is, check the nearest point on the actual geometry
1991                         clippointtosurface(surface, p, clipped);
1992                         VectorSubtract(clipped, p, clipped);
1993                         dist += VectorLength2(clipped);
1994                         if (dist < bestdist)
1995                         {
1996                                 // that's closer too, store it as the best match
1997                                 best = surfacenum;
1998                                 bestdist = dist;
1999                         }
2000                 }
2001         }
2002         PRVM_G_FLOAT(OFS_RETURN) = best;
2003 }
2004 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2005 void PF_getsurfaceclippedpoint(void)
2006 {
2007         prvm_edict_t *ed;
2008         msurface_t *surface;
2009         vec3_t p, out;
2010         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2011         ed = PRVM_G_EDICT(OFS_PARM0);
2012         if (!ed || ed->priv.server->free)
2013                 return;
2014         if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
2015                 return;
2016         // FIXME: implement rotation/scaling
2017         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2018         clippointtosurface(surface, p, out);
2019         // FIXME: implement rotation/scaling
2020         VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2021 }
2022
2023 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2024 //this function originally written by KrimZon, made shorter by LordHavoc
2025 void PF_clientcommand (void)
2026 {
2027         client_t *temp_client;
2028         int i;
2029
2030         //find client for this entity
2031         i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2032         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2033         {
2034                 Con_Print("PF_clientcommand: entity is not a client\n");
2035                 return;
2036         }
2037
2038         temp_client = host_client;
2039         host_client = svs.clients + i;
2040         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2041         host_client = temp_client;
2042 }
2043
2044 //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)
2045 void PF_setattachment (void)
2046 {
2047         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2048         prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2049         const char *tagname = PRVM_G_STRING(OFS_PARM2);
2050         prvm_eval_t *v;
2051         int modelindex;
2052         model_t *model;
2053
2054         if (e == prog->edicts)
2055                 PF_WARNING("setattachment: can not modify world entity\n");
2056         if (e->priv.server->free)
2057                 PF_WARNING("setattachment: can not modify free entity\n");
2058
2059         if (tagentity == NULL)
2060                 tagentity = prog->edicts;
2061
2062         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
2063         if (v)
2064                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2065
2066         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
2067         if (v)
2068                 v->_float = 0;
2069         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2070         {
2071                 modelindex = (int)tagentity->fields.server->modelindex;
2072                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
2073                 {
2074                         v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->fields.server->skin, tagname);
2075                         if (v->_float == 0)
2076                                 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);
2077                 }
2078                 else
2079                         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));
2080         }
2081 }
2082
2083 /////////////////////////////////////////
2084 // DP_MD3_TAGINFO extension coded by VorteX
2085
2086 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2087 {
2088         int i;
2089         model_t *model;
2090
2091         i = e->fields.server->modelindex;
2092         if (i < 1 || i >= MAX_MODELS)
2093                 return -1;
2094         model = sv.models[i];
2095
2096         return Mod_Alias_GetTagIndexForName(model, e->fields.server->skin, tagname);
2097 };
2098
2099 // Warnings/errors code:
2100 // 0 - normal (everything all-right)
2101 // 1 - world entity
2102 // 2 - free entity
2103 // 3 - null or non-precached model
2104 // 4 - no tags with requested index
2105 // 5 - runaway loop at attachment chain
2106 extern cvar_t cl_bob;
2107 extern cvar_t cl_bobcycle;
2108 extern cvar_t cl_bobup;
2109 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2110 {
2111         prvm_eval_t *val;
2112         int modelindex, reqframe, attachloop;
2113         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2114         prvm_edict_t *attachent;
2115         model_t *model;
2116
2117         Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
2118
2119         if (ent == prog->edicts)
2120                 return 1;
2121         if (ent->priv.server->free)
2122                 return 2;
2123
2124         modelindex = (int)ent->fields.server->modelindex;
2125         if (modelindex <= 0 || modelindex > MAX_MODELS)
2126                 return 3;
2127
2128         model = sv.models[modelindex];
2129
2130         if (ent->fields.server->frame >= 0 && ent->fields.server->frame < model->numframes && model->animscenes)
2131                 reqframe = model->animscenes[(int)ent->fields.server->frame].firstframe;
2132         else
2133                 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2134
2135         // get initial tag matrix
2136         if (tagindex)
2137         {
2138                 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2139                 if (ret)
2140                         return ret;
2141         }
2142         else
2143                 Matrix4x4_CreateIdentity(&tagmatrix);
2144
2145         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
2146         { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2147                 attachloop = 0;
2148                 do
2149                 {
2150                         attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2151                         val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index);
2152                         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)
2153                                 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.server->frame].firstframe, val->_float - 1, &attachmatrix);
2154                         else
2155                                 Matrix4x4_CreateIdentity(&attachmatrix);
2156
2157                         // apply transformation by child entity matrix
2158                         val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
2159                         if (val->_float == 0)
2160                                 val->_float = 1;
2161                         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);
2162                         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2163                         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]);
2164                         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]);
2165                         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]);
2166                         Matrix4x4_Copy(&tagmatrix, out);
2167
2168                         // finally transformate by matrix of tag on parent entity
2169                         Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2170                         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];
2171                         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];
2172                         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];
2173                         Matrix4x4_Copy(&tagmatrix, out);
2174
2175                         ent = attachent;
2176                         attachloop += 1;
2177                         if (attachloop > 255) // prevent runaway looping
2178                                 return 5;
2179                 }
2180                 while ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
2181         }
2182
2183         // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2184         val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
2185         if (val->_float == 0)
2186                 val->_float = 1;
2187         // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2188         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);
2189         Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2190         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]);
2191         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]);
2192         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]);
2193
2194         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
2195         {// RENDER_VIEWMODEL magic
2196                 Matrix4x4_Copy(&tagmatrix, out);
2197                 ent = PRVM_EDICT_NUM(val->edict);
2198
2199                 val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
2200                 if (val->_float == 0)
2201                         val->_float = 1;
2202
2203                 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);
2204                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2205                 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]);
2206                 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]);
2207                 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]);
2208
2209                 /*
2210                 // Cl_bob, ported from rendering code
2211                 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2212                 {
2213                         double bob, cycle;
2214                         // LordHavoc: this code is *weird*, but not replacable (I think it
2215                         // should be done in QC on the server, but oh well, quake is quake)
2216                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2217                         // degrees (which allows lengthening or squishing the peak or valley)
2218                         cycle = sv.time/cl_bobcycle.value;
2219                         cycle -= (int)cycle;
2220                         if (cycle < cl_bobup.value)
2221                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2222                         else
2223                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2224                         // bob is proportional to velocity in the xy plane
2225                         // (don't count Z, or jumping messes it up)
2226                         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;
2227                         bob = bob*0.3 + bob*0.7*cycle;
2228                         out->m[2][3] += bound(-7, bob, 4);
2229                 }
2230                 */
2231         }
2232         return 0;
2233 }
2234
2235 //float(entity ent, string tagname) gettagindex;
2236
2237 void PF_gettagindex (void)
2238 {
2239         prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
2240         const char *tag_name = PRVM_G_STRING(OFS_PARM1);
2241         int modelindex, tag_index;
2242
2243         if (ent == prog->edicts)
2244                 PF_WARNING("gettagindex: can't affect world entity\n");
2245         if (ent->priv.server->free)
2246                 PF_WARNING("gettagindex: can't affect free entity\n");
2247
2248         modelindex = (int)ent->fields.server->modelindex;
2249         tag_index = 0;
2250         if (modelindex <= 0 || modelindex > MAX_MODELS)
2251                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2252         else
2253         {
2254                 tag_index = SV_GetTagIndex(ent, tag_name);
2255                 if (tag_index == 0)
2256                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2257         }
2258         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2259 };
2260
2261 //vector(entity ent, float tagindex) gettaginfo;
2262 void PF_gettaginfo (void)
2263 {
2264         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2265         int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2266         matrix4x4_t tag_matrix;
2267         int returncode;
2268
2269         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2270         Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2271
2272         switch(returncode)
2273         {
2274                 case 1:
2275                         PF_WARNING("gettagindex: can't affect world entity\n");
2276                         break;
2277                 case 2:
2278                         PF_WARNING("gettagindex: can't affect free entity\n");
2279                         break;
2280                 case 3:
2281                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2282                         break;
2283                 case 4:
2284                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2285                         break;
2286                 case 5:
2287                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2288                         break;
2289         }
2290 }
2291
2292 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2293 void PF_dropclient (void)
2294 {
2295         int clientnum;
2296         client_t *oldhostclient;
2297         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2298         if (clientnum < 0 || clientnum >= svs.maxclients)
2299                 PF_WARNING("dropclient: not a client\n");
2300         if (!svs.clients[clientnum].active)
2301                 PF_WARNING("dropclient: that client slot is not connected\n");
2302         oldhostclient = host_client;
2303         host_client = svs.clients + clientnum;
2304         SV_DropClient(false);
2305         host_client = oldhostclient;
2306 }
2307
2308 //entity() spawnclient (DP_SV_BOTCLIENT)
2309 void PF_spawnclient (void)
2310 {
2311         int i;
2312         prvm_edict_t    *ed;
2313         prog->xfunction->builtinsprofile += 2;
2314         ed = prog->edicts;
2315         for (i = 0;i < svs.maxclients;i++)
2316         {
2317                 if (!svs.clients[i].active)
2318                 {
2319                         prog->xfunction->builtinsprofile += 100;
2320                         SV_ConnectClient (i, NULL);
2321                         ed = PRVM_EDICT_NUM(i + 1);
2322                         break;
2323                 }
2324         }
2325         VM_RETURN_EDICT(ed);
2326 }
2327
2328 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2329 void PF_clienttype (void)
2330 {
2331         int clientnum;
2332         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2333         if (clientnum < 0 || clientnum >= svs.maxclients)
2334                 PRVM_G_FLOAT(OFS_RETURN) = 3;
2335         else if (!svs.clients[clientnum].active)
2336                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2337         else if (svs.clients[clientnum].netconnection)
2338                 PRVM_G_FLOAT(OFS_RETURN) = 1;
2339         else
2340                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2341 }
2342
2343 prvm_builtin_t vm_sv_builtins[] = {
2344 NULL,                                           // #0
2345 PF_makevectors,                         // #1 void(entity e) makevectors
2346 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
2347 PF_setmodel,                            // #3 void(entity e, string m) setmodel
2348 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
2349 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
2350 VM_break,                                       // #6 void() break
2351 VM_random,                                      // #7 float() random
2352 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
2353 VM_normalize,                           // #9 vector(vector v) normalize
2354 VM_error,                                       // #10 void(string e) error
2355 VM_objerror,                            // #11 void(string e) objerror
2356 VM_vlen,                                        // #12 float(vector v) vlen
2357 VM_vectoyaw,                            // #13 float(vector v) vectoyaw
2358 VM_spawn,                                       // #14 entity() spawn
2359 VM_remove,                                      // #15 void(entity e) remove
2360 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
2361 PF_checkclient,                         // #17 entity() clientlist
2362 VM_find,                                        // #18 entity(entity start, .string fld, string match) find
2363 PF_precache_sound,                      // #19 void(string s) precache_sound
2364 PF_precache_model,                      // #20 void(string s) precache_model
2365 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
2366 PF_findradius,                          // #22 entity(vector org, float rad) findradius
2367 VM_bprint,                                      // #23 void(string s) bprint
2368 PF_sprint,                                      // #24 void(entity client, string s) sprint
2369 VM_dprint,                                      // #25 void(string s) dprint
2370 VM_ftos,                                        // #26 void(string s) ftos
2371 VM_vtos,                                        // #27 void(string s) vtos
2372 VM_coredump,                            // #28 void() coredump
2373 VM_traceon,                                     // #29 void() traceon
2374 VM_traceoff,                            // #30 void() traceoff
2375 VM_eprint,                                      // #31 void(entity e) eprint
2376 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
2377 NULL,                                           // #33
2378 PF_droptofloor,                         // #34 float() droptofloor
2379 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
2380 VM_rint,                                        // #36 float(float v) rint
2381 VM_floor,                                       // #37 float(float v) floor
2382 VM_ceil,                                        // #38 float(float v) ceil
2383 NULL,                                           // #39
2384 PF_checkbottom,                         // #40 float(entity e) checkbottom
2385 PF_pointcontents,                       // #41 float(vector v) pointcontents
2386 NULL,                                           // #42
2387 VM_fabs,                                        // #43 float(float f) fabs
2388 PF_aim,                                         // #44 vector(entity e, float speed) aim
2389 VM_cvar,                                        // #45 float(string s) cvar
2390 VM_localcmd,                            // #46 void(string s) localcmd
2391 VM_nextent,                                     // #47 entity(entity e) nextent
2392 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
2393 PF_changeyaw,                           // #49 void() ChangeYaw
2394 NULL,                                           // #50
2395 VM_vectoangles,                         // #51 vector(vector v) vectoangles
2396 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
2397 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
2398 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
2399 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
2400 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
2401 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
2402 PF_WriteString,                         // #58 void(float to, string s) WriteString
2403 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
2404 VM_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2405 VM_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2406 VM_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2407 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2408 PF_tracetoss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2409 VM_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
2410 NULL,                                           // #66
2411 SV_MoveToGoal,                          // #67 void(float step) movetogoal
2412 PF_precache_file,                       // #68 string(string s) precache_file
2413 PF_makestatic,                          // #69 void(entity e) makestatic
2414 VM_changelevel,                         // #70 void(string s) changelevel
2415 NULL,                                           // #71
2416 VM_cvar_set,                            // #72 void(string var, string val) cvar_set
2417 PF_centerprint,                         // #73 void(entity client, strings) centerprint
2418 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2419 PF_precache_model,                      // #75 string(string s) precache_model2
2420 PF_precache_sound,                      // #76 string(string s) precache_sound2
2421 PF_precache_file,                       // #77 string(string s) precache_file2
2422 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
2423 NULL,                                           // #79
2424 NULL,                                           // #80
2425 VM_stof,                                        // #81 float(string s) stof (FRIK_FILE)
2426 NULL,                                           // #82
2427 NULL,                                           // #83
2428 NULL,                                           // #84
2429 NULL,                                           // #85
2430 NULL,                                           // #86
2431 NULL,                                           // #87
2432 NULL,                                           // #88
2433 NULL,                                           // #89
2434 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2435 VM_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
2436 PF_getlight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2437 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2438 VM_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2439 VM_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2440 VM_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2441 VM_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2442 VM_findfloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2443 VM_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
2444 NULL,                                           // #100
2445 NULL,                                           // #101
2446 NULL,                                           // #102
2447 NULL,                                           // #103
2448 NULL,                                           // #104
2449 NULL,                                           // #105
2450 NULL,                                           // #106
2451 NULL,                                           // #107
2452 NULL,                                           // #108
2453 NULL,                                           // #109
2454 VM_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
2455 VM_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
2456 VM_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
2457 VM_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2458 VM_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
2459 VM_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
2460 VM_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
2461 VM_stov,                                        // #117 vector(string) stov (FRIK_FILE)
2462 VM_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
2463 VM_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
2464 e10, e10, e10, e10, e10, e10, e10, e10,         // #120-199
2465 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10,       // #200-299
2466 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10,       // #300-399
2467 VM_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
2468 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
2469 VM_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
2470 VM_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
2471 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2472 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2473 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2474 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2475 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2476 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2477 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2478 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
2479 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2480 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2481 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2482 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2483 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2484 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2485 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2486 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2487 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2488 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2489 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2490 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2491 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2492 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2493 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2494 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2495 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
2496 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
2497 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
2498 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
2499 PF_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
2500 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
2501 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
2502 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
2503 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
2504 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
2505 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
2506 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
2507 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
2508 VM_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
2509 VM_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
2510 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
2511 VM_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
2512 VM_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
2513 VM_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
2514 VM_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
2515 VM_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
2516 PF_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
2517 PF_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
2518 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2519 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2520 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
2521 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
2522 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
2523 NULL,                                           // #456
2524 NULL,                                           // #457
2525 NULL,                                           // #458
2526 NULL,                                           // #459
2527 e10, e10, e10, e10                      // #460-499 (LordHavoc)
2528 };
2529
2530 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2531
2532 void VM_SV_Cmd_Init(void)
2533 {
2534         VM_Cmd_Init();
2535 }
2536
2537 void VM_SV_Cmd_Reset(void)
2538 {
2539         VM_Cmd_Reset();
2540 }
2541