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