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