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