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