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