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