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