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