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