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