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