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