added PRVM_64 define which upgrades the QC VM to double precision
[xonotic/darkplaces.git] / svvm_cmds.c
1 #include "quakedef.h"
2
3 #include "prvm_cmds.h"
4 #include "jpeg.h"
5
6 //============================================================================
7 // Server
8
9
10
11 const char *vm_sv_extensions =
12 "BX_WAL_SUPPORT "
13 "DP_BUTTONCHAT "
14 "DP_BUTTONUSE "
15 "DP_CL_LOADSKY "
16 "DP_CON_ALIASPARAMETERS "
17 "DP_CON_BESTWEAPON "
18 "DP_CON_EXPANDCVAR "
19 "DP_CON_SET "
20 "DP_CON_SETA "
21 "DP_CON_STARTMAP "
22 "DP_CRYPTO "
23 "DP_CSQC_BINDMAPS "
24 "DP_CSQC_ENTITYWORLDOBJECT "
25 "DP_CSQC_ENTITYMODELLIGHT "
26 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
27 "DP_CSQC_MAINVIEW "
28 "DP_CSQC_MINFPS_QUALITY "
29 "DP_CSQC_MULTIFRAME_INTERPOLATION "
30 "DP_CSQC_BOXPARTICLES "
31 "DP_CSQC_SPAWNPARTICLE "
32 "DP_CSQC_QUERYRENDERENTITY "
33 "DP_CSQC_ROTATEMOVES "
34 "DP_CSQC_SETPAUSE "
35 "DP_CSQC_V_CALCREFDEF_WIP1 "
36 "DP_CSQC_V_CALCREFDEF_WIP2 "
37 "DP_EF_ADDITIVE "
38 "DP_EF_BLUE "
39 "DP_EF_DOUBLESIDED "
40 "DP_EF_DYNAMICMODELLIGHT "
41 "DP_EF_FLAME "
42 "DP_EF_FULLBRIGHT "
43 "DP_EF_NODEPTHTEST "
44 "DP_EF_NODRAW "
45 "DP_EF_NOGUNBOB "
46 "DP_EF_NOSELFSHADOW "
47 "DP_EF_NOSHADOW "
48 "DP_EF_RED "
49 "DP_EF_RESTARTANIM_BIT "
50 "DP_EF_STARDUST "
51 "DP_EF_TELEPORT_BIT "
52 "DP_ENT_ALPHA "
53 "DP_ENT_COLORMOD "
54 "DP_ENT_CUSTOMCOLORMAP "
55 "DP_ENT_EXTERIORMODELTOCLIENT "
56 "DP_ENT_GLOW "
57 "DP_ENT_GLOWMOD "
58 "DP_ENT_LOWPRECISION "
59 "DP_ENT_SCALE "
60 "DP_ENT_TRAILEFFECTNUM "
61 "DP_ENT_VIEWMODEL "
62 "DP_GFX_EXTERNALTEXTURES "
63 "DP_GFX_EXTERNALTEXTURES_PERMAP "
64 "DP_GFX_FOG "
65 "DP_GFX_MODEL_INTERPOLATION "
66 "DP_GFX_QUAKE3MODELTAGS "
67 "DP_GFX_SKINFILES "
68 "DP_GFX_SKYBOX "
69 "DP_GFX_FONTS "
70 "DP_GFX_FONTS_FREETYPE "
71 "DP_UTF8 "
72 "DP_FONT_VARIABLEWIDTH "
73 "DP_HALFLIFE_MAP "
74 "DP_HALFLIFE_MAP_CVAR "
75 "DP_HALFLIFE_SPRITE "
76 "DP_INPUTBUTTONS "
77 "DP_LIGHTSTYLE_STATICVALUE "
78 "DP_LITSPRITES "
79 "DP_LITSUPPORT "
80 "DP_MONSTERWALK "
81 "DP_MOVETYPEBOUNCEMISSILE "
82 "DP_MOVETYPEFLYWORLDONLY "
83 "DP_MOVETYPEFOLLOW "
84 "DP_NULL_MODEL "
85 "DP_QC_ASINACOSATANATAN2TAN "
86 "DP_QC_AUTOCVARS "
87 "DP_QC_CHANGEPITCH "
88 "DP_QC_CMD "
89 "DP_QC_COPYENTITY "
90 "DP_QC_CRC16 "
91 "DP_QC_CVAR_DEFSTRING "
92 "DP_QC_CVAR_DESCRIPTION "
93 "DP_QC_CVAR_STRING "
94 "DP_QC_CVAR_TYPE "
95 "DP_QC_DIGEST "
96 "DP_QC_DIGEST_SHA256 "
97 "DP_QC_EDICT_NUM "
98 "DP_QC_ENTITYDATA "
99 "DP_QC_ENTITYSTRING "
100 "DP_QC_ETOS "
101 "DP_QC_EXTRESPONSEPACKET "
102 "DP_QC_FINDCHAIN "
103 "DP_QC_FINDCHAINFLAGS "
104 "DP_QC_FINDCHAINFLOAT "
105 "DP_QC_FINDCHAIN_TOFIELD "
106 "DP_QC_FINDFLAGS "
107 "DP_QC_FINDFLOAT "
108 "DP_QC_FS_SEARCH "
109 "DP_QC_GETLIGHT "
110 "DP_QC_GETSURFACE "
111 "DP_QC_GETSURFACETRIANGLE "
112 "DP_QC_GETSURFACEPOINTATTRIBUTE "
113 "DP_QC_GETTAGINFO "
114 "DP_QC_GETTAGINFO_BONEPROPERTIES "
115 "DP_QC_GETTIME "
116 "DP_QC_GETTIME_CDTRACK "
117 "DP_QC_I18N "
118 "DP_QC_LOG "
119 "DP_QC_MINMAXBOUND "
120 "DP_QC_MULTIPLETEMPSTRINGS "
121 "DP_QC_NUM_FOR_EDICT "
122 "DP_QC_RANDOMVEC "
123 "DP_QC_SINCOSSQRTPOW "
124 "DP_QC_SPRINTF "
125 "DP_QC_STRFTIME "
126 "DP_QC_STRINGBUFFERS "
127 "DP_QC_STRINGBUFFERS_CVARLIST "
128 "DP_QC_STRINGBUFFERS_EXT_WIP "
129 "DP_QC_STRINGCOLORFUNCTIONS "
130 "DP_QC_STRING_CASE_FUNCTIONS "
131 "DP_QC_STRREPLACE "
132 "DP_QC_TOKENIZEBYSEPARATOR "
133 "DP_QC_TOKENIZE_CONSOLE "
134 "DP_QC_TRACEBOX "
135 "DP_QC_TRACETOSS "
136 "DP_QC_TRACE_MOVETYPE_HITMODEL "
137 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
138 "DP_QC_UNLIMITEDTEMPSTRINGS "
139 "DP_QC_URI_ESCAPE "
140 "DP_QC_URI_GET "
141 "DP_QC_URI_POST "
142 "DP_QC_VECTOANGLES_WITH_ROLL "
143 "DP_QC_VECTORVECTORS "
144 "DP_QC_WHICHPACK "
145 "DP_QUAKE2_MODEL "
146 "DP_QUAKE2_SPRITE "
147 "DP_QUAKE3_MAP "
148 "DP_QUAKE3_MODEL "
149 "DP_REGISTERCVAR "
150 "DP_SKELETONOBJECTS "
151 "DP_SND_DIRECTIONLESSATTNNONE "
152 "DP_SND_FAKETRACKS "
153 "DP_SND_SOUND7_WIP1 "
154 "DP_SND_SOUND7_WIP2 "
155 "DP_SND_OGGVORBIS "
156 "DP_SND_SETPARAMS "
157 "DP_SND_STEREOWAV "
158 "DP_SND_GETSOUNDTIME "
159 "DP_VIDEO_DPV "
160 "DP_VIDEO_SUBTITLES "
161 "DP_SOLIDCORPSE "
162 "DP_SPRITE32 "
163 "DP_SV_BOTCLIENT "
164 "DP_SV_BOUNCEFACTOR "
165 "DP_SV_CLIENTCAMERA "
166 "DP_SV_CLIENTCOLORS "
167 "DP_SV_CLIENTNAME "
168 "DP_SV_CMD "
169 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
170 "DP_SV_DISCARDABLEDEMO "
171 "DP_SV_DRAWONLYTOCLIENT "
172 "DP_SV_DROPCLIENT "
173 "DP_SV_EFFECT "
174 "DP_SV_ENTITYCONTENTSTRANSITION "
175 "DP_SV_MODELFLAGS_AS_EFFECTS "
176 "DP_SV_MOVETYPESTEP_LANDEVENT "
177 "DP_SV_NETADDRESS "
178 "DP_SV_NODRAWTOCLIENT "
179 "DP_SV_ONENTITYNOSPAWNFUNCTION "
180 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
181 "DP_SV_PING "
182 "DP_SV_PING_PACKETLOSS "
183 "DP_SV_PLAYERPHYSICS "
184 "DP_PHYSICS_ODE "
185 "DP_SV_POINTPARTICLES "
186 "DP_SV_POINTSOUND "
187 "DP_SV_PRECACHEANYTIME "
188 "DP_SV_PRINT "
189 "DP_SV_PUNCHVECTOR "
190 "DP_SV_QCSTATUS "
191 "DP_SV_ROTATINGBMODEL "
192 "DP_SV_SETCOLOR "
193 "DP_SV_SHUTDOWN "
194 "DP_SV_SLOWMO "
195 "DP_SV_SPAWNFUNC_PREFIX "
196 "DP_SV_WRITEPICTURE "
197 "DP_SV_WRITEUNTERMINATEDSTRING "
198 "DP_TE_BLOOD "
199 "DP_TE_BLOODSHOWER "
200 "DP_TE_CUSTOMFLASH "
201 "DP_TE_EXPLOSIONRGB "
202 "DP_TE_FLAMEJET "
203 "DP_TE_PARTICLECUBE "
204 "DP_TE_PARTICLERAIN "
205 "DP_TE_PARTICLESNOW "
206 "DP_TE_PLASMABURN "
207 "DP_TE_QUADEFFECTS1 "
208 "DP_TE_SMALLFLASH "
209 "DP_TE_SPARK "
210 "DP_TE_STANDARDEFFECTBUILTINS "
211 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
212 "DP_VIEWZOOM "
213 "EXT_BITSHIFT "
214 "FRIK_FILE "
215 "FTE_CSQC_SKELETONOBJECTS "
216 "FTE_QC_CHECKPVS "
217 "FTE_STRINGS "
218 "KRIMZON_SV_PARSECLIENTCOMMAND "
219 "NEH_CMD_PLAY2 "
220 "NEH_RESTOREGAME "
221 "NEXUIZ_PLAYERMODEL "
222 "NXQ_GFX_LETTERBOX "
223 "PRYDON_CLIENTCURSOR "
224 "TENEBRAE_GFX_DLIGHTS "
225 "TW_SV_STEPCONTROL "
226 "ZQ_PAUSE "
227 //"EXT_CSQC " // not ready yet
228 ;
229
230 /*
231 =================
232 VM_SV_setorigin
233
234 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.
235
236 setorigin (entity, origin)
237 =================
238 */
239 static void VM_SV_setorigin(prvm_prog_t *prog)
240 {
241         prvm_edict_t    *e;
242
243         VM_SAFEPARMCOUNT(2, VM_setorigin);
244
245         e = PRVM_G_EDICT(OFS_PARM0);
246         if (e == prog->edicts)
247         {
248                 VM_Warning(prog, "setorigin: can not modify world entity\n");
249                 return;
250         }
251         if (e->priv.server->free)
252         {
253                 VM_Warning(prog, "setorigin: can not modify free entity\n");
254                 return;
255         }
256         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), PRVM_serveredictvector(e, origin));
257         if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
258                 e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
259         SV_LinkEdict(e);
260 }
261
262 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
263 static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max, qboolean rotate)
264 {
265         int             i;
266
267         for (i=0 ; i<3 ; i++)
268                 if (min[i] > max[i])
269                         prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
270
271 // set derived values
272         VectorCopy (min, PRVM_serveredictvector(e, mins));
273         VectorCopy (max, PRVM_serveredictvector(e, maxs));
274         VectorSubtract (max, min, PRVM_serveredictvector(e, size));
275
276         SV_LinkEdict(e);
277 }
278
279 /*
280 =================
281 VM_SV_setsize
282
283 the size box is rotated by the current angle
284 LordHavoc: no it isn't...
285
286 setsize (entity, minvector, maxvector)
287 =================
288 */
289 static void VM_SV_setsize(prvm_prog_t *prog)
290 {
291         prvm_edict_t    *e;
292         vec3_t mins, maxs;
293
294         VM_SAFEPARMCOUNT(3, VM_setsize);
295
296         e = PRVM_G_EDICT(OFS_PARM0);
297         if (e == prog->edicts)
298         {
299                 VM_Warning(prog, "setsize: can not modify world entity\n");
300                 return;
301         }
302         if (e->priv.server->free)
303         {
304                 VM_Warning(prog, "setsize: can not modify free entity\n");
305                 return;
306         }
307         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
308         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
309         SetMinMaxSize(prog, e, mins, maxs, false);
310 }
311
312
313 /*
314 =================
315 VM_SV_setmodel
316
317 setmodel(entity, model)
318 =================
319 */
320 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
321 static void VM_SV_setmodel(prvm_prog_t *prog)
322 {
323         prvm_edict_t    *e;
324         dp_model_t      *mod;
325         int             i;
326
327         VM_SAFEPARMCOUNT(2, VM_setmodel);
328
329         e = PRVM_G_EDICT(OFS_PARM0);
330         if (e == prog->edicts)
331         {
332                 VM_Warning(prog, "setmodel: can not modify world entity\n");
333                 return;
334         }
335         if (e->priv.server->free)
336         {
337                 VM_Warning(prog, "setmodel: can not modify free entity\n");
338                 return;
339         }
340         i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
341         PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
342         PRVM_serveredictfloat(e, modelindex) = i;
343
344         mod = SV_GetModelByIndex(i);
345
346         if (mod)
347         {
348                 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
349                         SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
350                 else
351                         SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
352         }
353         else
354                 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
355 }
356
357 /*
358 =================
359 VM_SV_sprint
360
361 single print to a specific client
362
363 sprint(clientent, value)
364 =================
365 */
366 static void VM_SV_sprint(prvm_prog_t *prog)
367 {
368         client_t        *client;
369         int                     entnum;
370         char string[VM_STRINGTEMP_LENGTH];
371
372         VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
373
374         VM_VarString(prog, 1, string, sizeof(string));
375
376         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
377         // LordHavoc: div0 requested that sprintto world  operate like print
378         if (entnum == 0)
379         {
380                 Con_Print(string);
381                 return;
382         }
383
384         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
385         {
386                 VM_Warning(prog, "tried to centerprint to a non-client\n");
387                 return;
388         }
389
390         client = svs.clients + entnum-1;
391         if (!client->netconnection)
392                 return;
393
394         MSG_WriteChar(&client->netconnection->message,svc_print);
395         MSG_WriteString(&client->netconnection->message, string);
396 }
397
398
399 /*
400 =================
401 VM_SV_centerprint
402
403 single print to a specific client
404
405 centerprint(clientent, value)
406 =================
407 */
408 static void VM_SV_centerprint(prvm_prog_t *prog)
409 {
410         client_t        *client;
411         int                     entnum;
412         char string[VM_STRINGTEMP_LENGTH];
413
414         VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
415
416         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
417
418         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
419         {
420                 VM_Warning(prog, "tried to centerprint to a non-client\n");
421                 return;
422         }
423
424         client = svs.clients + entnum-1;
425         if (!client->netconnection)
426                 return;
427
428         VM_VarString(prog, 1, string, sizeof(string));
429         MSG_WriteChar(&client->netconnection->message,svc_centerprint);
430         MSG_WriteString(&client->netconnection->message, string);
431 }
432
433 /*
434 =================
435 VM_SV_particle
436
437 particle(origin, color, count)
438 =================
439 */
440 static void VM_SV_particle(prvm_prog_t *prog)
441 {
442         vec3_t          org, dir;
443         float           color;
444         float           count;
445
446         VM_SAFEPARMCOUNT(4, VM_SV_particle);
447
448         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
449         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
450         color = PRVM_G_FLOAT(OFS_PARM2);
451         count = PRVM_G_FLOAT(OFS_PARM3);
452         SV_StartParticle (org, dir, (int)color, (int)count);
453 }
454
455
456 /*
457 =================
458 VM_SV_ambientsound
459
460 =================
461 */
462 static void VM_SV_ambientsound(prvm_prog_t *prog)
463 {
464         const char      *samp;
465         vec3_t          pos;
466         float           vol, attenuation;
467         int                     soundnum, large;
468
469         VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
470
471         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
472         samp = PRVM_G_STRING(OFS_PARM1);
473         vol = PRVM_G_FLOAT(OFS_PARM2);
474         attenuation = PRVM_G_FLOAT(OFS_PARM3);
475
476 // check to see if samp was properly precached
477         soundnum = SV_SoundIndex(samp, 1);
478         if (!soundnum)
479                 return;
480
481         large = false;
482         if (soundnum >= 256)
483                 large = true;
484
485         // add an svc_spawnambient command to the level signon packet
486
487         if (large)
488                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
489         else
490                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
491
492         MSG_WriteVector(&sv.signon, pos, sv.protocol);
493
494         if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
495                 MSG_WriteShort (&sv.signon, soundnum);
496         else
497                 MSG_WriteByte (&sv.signon, soundnum);
498
499         MSG_WriteByte (&sv.signon, (int)(vol*255));
500         MSG_WriteByte (&sv.signon, (int)(attenuation*64));
501
502 }
503
504 /*
505 =================
506 VM_SV_sound
507
508 Each entity can have eight independant sound sources, like voice,
509 weapon, feet, etc.
510
511 Channel 0 is an auto-allocate channel, the others override anything
512 already running on that entity/channel pair.
513
514 An attenuation of 0 will play full volume everywhere in the level.
515 Larger attenuations will drop off.
516
517 =================
518 */
519 static void VM_SV_sound(prvm_prog_t *prog)
520 {
521         const char      *sample;
522         int                     channel;
523         prvm_edict_t            *entity;
524         int             volume;
525         int flags;
526         float attenuation;
527         float pitchchange;
528
529         VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
530
531         entity = PRVM_G_EDICT(OFS_PARM0);
532         channel = (int)PRVM_G_FLOAT(OFS_PARM1);
533         sample = PRVM_G_STRING(OFS_PARM2);
534         volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
535         if (prog->argc < 5)
536         {
537                 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
538                 attenuation = 1;
539         }
540         else
541                 attenuation = PRVM_G_FLOAT(OFS_PARM4);
542         if (prog->argc < 6)
543                 pitchchange = 0;
544         else
545                 pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
546
547         if (prog->argc < 7)
548         {
549                 flags = 0;
550                 if(channel >= 8 && channel <= 15) // weird QW feature
551                 {
552                         flags |= CHANFLAG_RELIABLE;
553                         channel -= 8;
554                 }
555         }
556         else
557                 flags = PRVM_G_FLOAT(OFS_PARM6);
558
559         if (volume < 0 || volume > 255)
560         {
561                 VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
562                 return;
563         }
564
565         if (attenuation < 0 || attenuation > 4)
566         {
567                 VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
568                 return;
569         }
570
571         channel = CHAN_USER2ENGINE(channel);
572
573         if (!IS_CHAN(channel))
574         {
575                 VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
576                 return;
577         }
578
579         SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANFLAG_RELIABLE, pitchchange);
580 }
581
582 /*
583 =================
584 VM_SV_pointsound
585
586 Follows the same logic as VM_SV_sound, except instead of
587 an entity, an origin for the sound is provided, and channel
588 is omitted (since no entity is being tracked).
589
590 =================
591 */
592 static void VM_SV_pointsound(prvm_prog_t *prog)
593 {
594         const char      *sample;
595         int             volume;
596         float           attenuation;
597         float           pitchchange;
598         vec3_t          org;
599
600         VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
601
602         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
603         sample = PRVM_G_STRING(OFS_PARM1);
604         volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
605         attenuation = PRVM_G_FLOAT(OFS_PARM3);
606         pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
607
608         if (volume < 0 || volume > 255)
609         {
610                 VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
611                 return;
612         }
613
614         if (attenuation < 0 || attenuation > 4)
615         {
616                 VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
617                 return;
618         }
619
620         SV_StartPointSound (org, sample, volume, attenuation, pitchchange);
621 }
622
623 /*
624 =================
625 VM_SV_traceline
626
627 Used for use tracing and shot targeting
628 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
629 if the tryents flag is set.
630
631 traceline (vector1, vector2, movetype, ignore)
632 =================
633 */
634 static void VM_SV_traceline(prvm_prog_t *prog)
635 {
636         vec3_t  v1, v2;
637         trace_t trace;
638         int             move;
639         prvm_edict_t    *ent;
640
641         VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
642
643         prog->xfunction->builtinsprofile += 30;
644
645         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
646         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
647         move = (int)PRVM_G_FLOAT(OFS_PARM2);
648         ent = PRVM_G_EDICT(OFS_PARM3);
649
650         if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
651                 prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
652
653         trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
654
655         VM_SetTraceGlobals(prog, &trace);
656 }
657
658
659 /*
660 =================
661 VM_SV_tracebox
662
663 Used for use tracing and shot targeting
664 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
665 if the tryents flag is set.
666
667 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
668 =================
669 */
670 // LordHavoc: added this for my own use, VERY useful, similar to traceline
671 static void VM_SV_tracebox(prvm_prog_t *prog)
672 {
673         vec3_t v1, v2, m1, m2;
674         trace_t trace;
675         int             move;
676         prvm_edict_t    *ent;
677
678         VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
679
680         prog->xfunction->builtinsprofile += 30;
681
682         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
683         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
684         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
685         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
686         move = (int)PRVM_G_FLOAT(OFS_PARM4);
687         ent = PRVM_G_EDICT(OFS_PARM5);
688
689         if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
690                 prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->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));
691
692         trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
693
694         VM_SetTraceGlobals(prog, &trace);
695 }
696
697 static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
698 {
699         int i;
700         float gravity;
701         vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
702         vec3_t original_origin;
703         vec3_t original_velocity;
704         vec3_t original_angles;
705         vec3_t original_avelocity;
706         trace_t trace;
707
708         VectorCopy(PRVM_serveredictvector(tossent, origin)   , original_origin   );
709         VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
710         VectorCopy(PRVM_serveredictvector(tossent, angles)   , original_angles   );
711         VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
712
713         gravity = PRVM_serveredictfloat(tossent, gravity);
714         if (!gravity)
715                 gravity = 1.0f;
716         gravity *= sv_gravity.value * 0.025;
717
718         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
719         {
720                 SV_CheckVelocity (tossent);
721                 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
722                 VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
723                 VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
724                 VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
725                 VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
726                 VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
727                 VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
728                 trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
729                 VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
730                 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
731
732                 if (trace.fraction < 1)
733                         break;
734         }
735
736         VectorCopy(original_origin   , PRVM_serveredictvector(tossent, origin)   );
737         VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
738         VectorCopy(original_angles   , PRVM_serveredictvector(tossent, angles)   );
739         VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
740
741         return trace;
742 }
743
744 static void VM_SV_tracetoss(prvm_prog_t *prog)
745 {
746         trace_t trace;
747         prvm_edict_t    *ent;
748         prvm_edict_t    *ignore;
749
750         VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
751
752         prog->xfunction->builtinsprofile += 600;
753
754         ent = PRVM_G_EDICT(OFS_PARM0);
755         if (ent == prog->edicts)
756         {
757                 VM_Warning(prog, "tracetoss: can not use world entity\n");
758                 return;
759         }
760         ignore = PRVM_G_EDICT(OFS_PARM1);
761
762         trace = SV_Trace_Toss(prog, ent, ignore);
763
764         VM_SetTraceGlobals(prog, &trace);
765 }
766
767 //============================================================================
768
769 static int checkpvsbytes;
770 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
771
772 static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
773 {
774         int             i;
775         prvm_edict_t    *ent;
776         vec3_t  org;
777
778 // cycle to the next one
779
780         check = bound(1, check, svs.maxclients);
781         if (check == svs.maxclients)
782                 i = 1;
783         else
784                 i = check + 1;
785
786         for ( ;  ; i++)
787         {
788                 // count the cost
789                 prog->xfunction->builtinsprofile++;
790                 // wrap around
791                 if (i == svs.maxclients+1)
792                         i = 1;
793                 // look up the client's edict
794                 ent = PRVM_EDICT_NUM(i);
795                 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
796                 if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
797                         continue;
798                 // found a valid client (possibly the same one again)
799                 break;
800         }
801
802 // get the PVS for the entity
803         VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
804         checkpvsbytes = 0;
805         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
806                 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
807
808         return i;
809 }
810
811 /*
812 =================
813 VM_SV_checkclient
814
815 Returns a client (or object that has a client enemy) that would be a
816 valid target.
817
818 If there is more than one valid option, they are cycled each frame
819
820 If (self.origin + self.viewofs) is not in the PVS of the current target,
821 it is not returned at all.
822
823 name checkclient ()
824 =================
825 */
826 int c_invis, c_notvis;
827 static void VM_SV_checkclient(prvm_prog_t *prog)
828 {
829         prvm_edict_t    *ent, *self;
830         vec3_t  view;
831
832         VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
833
834         // find a new check if on a new frame
835         if (sv.time - sv.lastchecktime >= 0.1)
836         {
837                 sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
838                 sv.lastchecktime = sv.time;
839         }
840
841         // return check if it might be visible
842         ent = PRVM_EDICT_NUM(sv.lastcheck);
843         if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
844         {
845                 VM_RETURN_EDICT(prog->edicts);
846                 return;
847         }
848
849         // if current entity can't possibly see the check entity, return 0
850         self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
851         VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
852         if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
853         {
854                 c_notvis++;
855                 VM_RETURN_EDICT(prog->edicts);
856                 return;
857         }
858
859         // might be able to see it
860         c_invis++;
861         VM_RETURN_EDICT(ent);
862 }
863
864 //============================================================================
865
866 /*
867 =================
868 VM_SV_checkpvs
869
870 Checks if an entity is in a point's PVS.
871 Should be fast but can be inexact.
872
873 float checkpvs(vector viewpos, entity viewee) = #240;
874 =================
875 */
876 static void VM_SV_checkpvs(prvm_prog_t *prog)
877 {
878         vec3_t viewpos, absmin, absmax;
879         prvm_edict_t *viewee;
880 #if 1
881         unsigned char *pvs;
882 #else
883         int fatpvsbytes;
884         unsigned char fatpvs[MAX_MAP_LEAFS/8];
885 #endif
886
887         VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
888         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
889         viewee = PRVM_G_EDICT(OFS_PARM1);
890
891         if(viewee->priv.server->free)
892         {
893                 VM_Warning(prog, "checkpvs: can not check free entity\n");
894                 PRVM_G_FLOAT(OFS_RETURN) = 4;
895                 return;
896         }
897
898 #if 1
899         if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
900         {
901                 // no PVS support on this worldmodel... darn
902                 PRVM_G_FLOAT(OFS_RETURN) = 3;
903                 return;
904         }
905         pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
906         if(!pvs)
907         {
908                 // viewpos isn't in any PVS... darn
909                 PRVM_G_FLOAT(OFS_RETURN) = 2;
910                 return;
911         }
912         VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
913         VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
914         PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
915 #else
916         // using fat PVS like FTEQW does (slow)
917         if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
918         {
919                 // no PVS support on this worldmodel... darn
920                 PRVM_G_FLOAT(OFS_RETURN) = 3;
921                 return;
922         }
923         fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
924         if(!fatpvsbytes)
925         {
926                 // viewpos isn't in any PVS... darn
927                 PRVM_G_FLOAT(OFS_RETURN) = 2;
928                 return;
929         }
930         VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
931         VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
932         PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
933 #endif
934 }
935
936
937 /*
938 =================
939 VM_SV_stuffcmd
940
941 Sends text over to the client's execution buffer
942
943 stuffcmd (clientent, value, ...)
944 =================
945 */
946 static void VM_SV_stuffcmd(prvm_prog_t *prog)
947 {
948         int             entnum;
949         client_t        *old;
950         char    string[VM_STRINGTEMP_LENGTH];
951
952         VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
953
954         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
955         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
956         {
957                 VM_Warning(prog, "Can't stuffcmd to a non-client\n");
958                 return;
959         }
960
961         VM_VarString(prog, 1, string, sizeof(string));
962
963         old = host_client;
964         host_client = svs.clients + entnum-1;
965         Host_ClientCommands ("%s", string);
966         host_client = old;
967 }
968
969 /*
970 =================
971 VM_SV_findradius
972
973 Returns a chain of entities that have origins within a spherical area
974
975 findradius (origin, radius)
976 =================
977 */
978 static void VM_SV_findradius(prvm_prog_t *prog)
979 {
980         prvm_edict_t *ent, *chain;
981         vec_t radius, radius2;
982         vec3_t org, eorg, mins, maxs;
983         int i;
984         int numtouchedicts;
985         static prvm_edict_t *touchedicts[MAX_EDICTS];
986         int chainfield;
987
988         VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
989
990         if(prog->argc == 3)
991                 chainfield = PRVM_G_INT(OFS_PARM2);
992         else
993                 chainfield = prog->fieldoffsets.chain;
994         if (chainfield < 0)
995                 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
996
997         chain = (prvm_edict_t *)prog->edicts;
998
999         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1000         radius = PRVM_G_FLOAT(OFS_PARM1);
1001         radius2 = radius * radius;
1002
1003         mins[0] = org[0] - (radius + 1);
1004         mins[1] = org[1] - (radius + 1);
1005         mins[2] = org[2] - (radius + 1);
1006         maxs[0] = org[0] + (radius + 1);
1007         maxs[1] = org[1] + (radius + 1);
1008         maxs[2] = org[2] + (radius + 1);
1009         numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1010         if (numtouchedicts > MAX_EDICTS)
1011         {
1012                 // this never happens
1013                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1014                 numtouchedicts = MAX_EDICTS;
1015         }
1016         for (i = 0;i < numtouchedicts;i++)
1017         {
1018                 ent = touchedicts[i];
1019                 prog->xfunction->builtinsprofile++;
1020                 // Quake did not return non-solid entities but darkplaces does
1021                 // (note: this is the reason you can't blow up fallen zombies)
1022                 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1023                         continue;
1024                 // LordHavoc: compare against bounding box rather than center so it
1025                 // doesn't miss large objects, and use DotProduct instead of Length
1026                 // for a major speedup
1027                 VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
1028                 if (sv_gameplayfix_findradiusdistancetobox.integer)
1029                 {
1030                         eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
1031                         eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
1032                         eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
1033                 }
1034                 else
1035                         VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
1036                 if (DotProduct(eorg, eorg) < radius2)
1037                 {
1038                         PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
1039                         chain = ent;
1040                 }
1041         }
1042
1043         VM_RETURN_EDICT(chain);
1044 }
1045
1046 static void VM_SV_precache_sound(prvm_prog_t *prog)
1047 {
1048         VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1049         PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1050 }
1051
1052 static void VM_SV_precache_model(prvm_prog_t *prog)
1053 {
1054         VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1055         SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1056         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1057 }
1058
1059 /*
1060 ===============
1061 VM_SV_walkmove
1062
1063 float(float yaw, float dist[, settrace]) walkmove
1064 ===============
1065 */
1066 static void VM_SV_walkmove(prvm_prog_t *prog)
1067 {
1068         prvm_edict_t    *ent;
1069         float   yaw, dist;
1070         vec3_t  move;
1071         mfunction_t     *oldf;
1072         int     oldself;
1073         qboolean        settrace;
1074
1075         VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1076
1077         // assume failure if it returns early
1078         PRVM_G_FLOAT(OFS_RETURN) = 0;
1079
1080         ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1081         if (ent == prog->edicts)
1082         {
1083                 VM_Warning(prog, "walkmove: can not modify world entity\n");
1084                 return;
1085         }
1086         if (ent->priv.server->free)
1087         {
1088                 VM_Warning(prog, "walkmove: can not modify free entity\n");
1089                 return;
1090         }
1091         yaw = PRVM_G_FLOAT(OFS_PARM0);
1092         dist = PRVM_G_FLOAT(OFS_PARM1);
1093         settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1094
1095         if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1096                 return;
1097
1098         yaw = yaw*M_PI*2 / 360;
1099
1100         move[0] = cos(yaw)*dist;
1101         move[1] = sin(yaw)*dist;
1102         move[2] = 0;
1103
1104 // save program state, because SV_movestep may call other progs
1105         oldf = prog->xfunction;
1106         oldself = PRVM_serverglobaledict(self);
1107
1108         PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1109
1110
1111 // restore program state
1112         prog->xfunction = oldf;
1113         PRVM_serverglobaledict(self) = oldself;
1114 }
1115
1116 /*
1117 ===============
1118 VM_SV_droptofloor
1119
1120 void() droptofloor
1121 ===============
1122 */
1123
1124 static void VM_SV_droptofloor(prvm_prog_t *prog)
1125 {
1126         prvm_edict_t            *ent;
1127         vec3_t          end, entorigin, entmins, entmaxs;
1128         trace_t         trace;
1129
1130         VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1131
1132         // assume failure if it returns early
1133         PRVM_G_FLOAT(OFS_RETURN) = 0;
1134
1135         ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1136         if (ent == prog->edicts)
1137         {
1138                 VM_Warning(prog, "droptofloor: can not modify world entity\n");
1139                 return;
1140         }
1141         if (ent->priv.server->free)
1142         {
1143                 VM_Warning(prog, "droptofloor: can not modify free entity\n");
1144                 return;
1145         }
1146
1147         VectorCopy (PRVM_serveredictvector(ent, origin), end);
1148         end[2] -= 256;
1149
1150         if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1151                 if (sv_gameplayfix_unstickentities.integer)
1152                         SV_UnstickEntity(ent);
1153
1154         VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
1155         VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
1156         VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
1157         trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1158         if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1159         {
1160                 vec3_t offset, org;
1161                 VectorSet(offset, 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]), 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]), PRVM_serveredictvector(ent, mins)[2]);
1162                 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
1163                 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1164                 VectorSubtract(trace.endpos, offset, trace.endpos);
1165                 if (trace.startsolid)
1166                 {
1167                         Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1168                         if (sv_gameplayfix_unstickentities.integer)
1169                                 SV_UnstickEntity(ent);
1170                         SV_LinkEdict(ent);
1171                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1172                         PRVM_serveredictedict(ent, groundentity) = 0;
1173                         PRVM_G_FLOAT(OFS_RETURN) = 1;
1174                 }
1175                 else if (trace.fraction < 1)
1176                 {
1177                         Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1178                         VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1179                         if (sv_gameplayfix_unstickentities.integer)
1180                                 SV_UnstickEntity(ent);
1181                         SV_LinkEdict(ent);
1182                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1183                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1184                         PRVM_G_FLOAT(OFS_RETURN) = 1;
1185                         // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1186                         ent->priv.server->suspendedinairflag = true;
1187                 }
1188         }
1189         else
1190         {
1191                 if (trace.fraction != 1)
1192                 {
1193                         if (trace.fraction < 1)
1194                                 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1195                         SV_LinkEdict(ent);
1196                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1197                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1198                         PRVM_G_FLOAT(OFS_RETURN) = 1;
1199                         // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1200                         ent->priv.server->suspendedinairflag = true;
1201                 }
1202         }
1203 }
1204
1205 /*
1206 ===============
1207 VM_SV_lightstyle
1208
1209 void(float style, string value) lightstyle
1210 ===============
1211 */
1212 static void VM_SV_lightstyle(prvm_prog_t *prog)
1213 {
1214         int             style;
1215         const char      *val;
1216         client_t        *client;
1217         int                     j;
1218
1219         VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1220
1221         style = (int)PRVM_G_FLOAT(OFS_PARM0);
1222         val = PRVM_G_STRING(OFS_PARM1);
1223
1224         if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1225                 prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
1226         }
1227
1228 // change the string in sv
1229         strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1230
1231 // send message to all clients on this server
1232         if (sv.state != ss_active)
1233                 return;
1234
1235         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1236         {
1237                 if (client->active && client->netconnection)
1238                 {
1239                         MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1240                         MSG_WriteChar (&client->netconnection->message,style);
1241                         MSG_WriteString (&client->netconnection->message, val);
1242                 }
1243         }
1244 }
1245
1246 /*
1247 =============
1248 VM_SV_checkbottom
1249 =============
1250 */
1251 static void VM_SV_checkbottom(prvm_prog_t *prog)
1252 {
1253         VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1254         PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1255 }
1256
1257 /*
1258 =============
1259 VM_SV_pointcontents
1260 =============
1261 */
1262 static void VM_SV_pointcontents(prvm_prog_t *prog)
1263 {
1264         vec3_t point;
1265         VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1266         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
1267         PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(point));
1268 }
1269
1270 /*
1271 =============
1272 VM_SV_aim
1273
1274 Pick a vector for the player to shoot along
1275 vector aim(entity, missilespeed)
1276 =============
1277 */
1278 static void VM_SV_aim(prvm_prog_t *prog)
1279 {
1280         prvm_edict_t    *ent, *check, *bestent;
1281         vec3_t  start, dir, end, bestdir;
1282         int             i, j;
1283         trace_t tr;
1284         float   dist, bestdist;
1285         //float speed;
1286
1287         VM_SAFEPARMCOUNT(2, VM_SV_aim);
1288
1289         // assume failure if it returns early
1290         VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1291         // if sv_aim is so high it can't possibly accept anything, skip out early
1292         if (sv_aim.value >= 1)
1293                 return;
1294
1295         ent = PRVM_G_EDICT(OFS_PARM0);
1296         if (ent == prog->edicts)
1297         {
1298                 VM_Warning(prog, "aim: can not use world entity\n");
1299                 return;
1300         }
1301         if (ent->priv.server->free)
1302         {
1303                 VM_Warning(prog, "aim: can not use free entity\n");
1304                 return;
1305         }
1306         //speed = PRVM_G_FLOAT(OFS_PARM1);
1307
1308         VectorCopy (PRVM_serveredictvector(ent, origin), start);
1309         start[2] += 20;
1310
1311 // try sending a trace straight
1312         VectorCopy (PRVM_serverglobalvector(v_forward), dir);
1313         VectorMA (start, 2048, dir, end);
1314         tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1315         if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
1316         && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
1317         {
1318                 VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1319                 return;
1320         }
1321
1322
1323 // try all possible entities
1324         VectorCopy (dir, bestdir);
1325         bestdist = sv_aim.value;
1326         bestent = NULL;
1327
1328         check = PRVM_NEXT_EDICT(prog->edicts);
1329         for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1330         {
1331                 prog->xfunction->builtinsprofile++;
1332                 if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
1333                         continue;
1334                 if (check == ent)
1335                         continue;
1336                 if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
1337                         continue;       // don't aim at teammate
1338                 for (j=0 ; j<3 ; j++)
1339                         end[j] = PRVM_serveredictvector(check, origin)[j]
1340                         + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
1341                 VectorSubtract (end, start, dir);
1342                 VectorNormalize (dir);
1343                 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1344                 if (dist < bestdist)
1345                         continue;       // to far to turn
1346                 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1347                 if (tr.ent == check)
1348                 {       // can shoot at this one
1349                         bestdist = dist;
1350                         bestent = check;
1351                 }
1352         }
1353
1354         if (bestent)
1355         {
1356                 VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
1357                 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1358                 VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
1359                 end[2] = dir[2];
1360                 VectorNormalize (end);
1361                 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1362         }
1363         else
1364         {
1365                 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1366         }
1367 }
1368
1369 /*
1370 ===============================================================================
1371
1372 MESSAGE WRITING
1373
1374 ===============================================================================
1375 */
1376
1377 #define MSG_BROADCAST   0               // unreliable to all
1378 #define MSG_ONE                 1               // reliable to one (msg_entity)
1379 #define MSG_ALL                 2               // reliable to all
1380 #define MSG_INIT                3               // write to the init string
1381 #define MSG_ENTITY              5
1382
1383 static sizebuf_t *WriteDest(prvm_prog_t *prog)
1384 {
1385         int             entnum;
1386         int             dest;
1387         prvm_edict_t    *ent;
1388
1389         dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1390         switch (dest)
1391         {
1392         case MSG_BROADCAST:
1393                 return &sv.datagram;
1394
1395         case MSG_ONE:
1396                 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
1397                 entnum = PRVM_NUM_FOR_EDICT(ent);
1398                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1399                 {
1400                         VM_Warning(prog, "WriteDest: tried to write to non-client\n");
1401                         return &sv.reliable_datagram;
1402                 }
1403                 else
1404                         return &svs.clients[entnum-1].netconnection->message;
1405
1406         default:
1407                 VM_Warning(prog, "WriteDest: bad destination\n");
1408         case MSG_ALL:
1409                 return &sv.reliable_datagram;
1410
1411         case MSG_INIT:
1412                 return &sv.signon;
1413
1414         case MSG_ENTITY:
1415                 return sv.writeentitiestoclient_msg;
1416         }
1417
1418         //return NULL;
1419 }
1420
1421 static void VM_SV_WriteByte(prvm_prog_t *prog)
1422 {
1423         VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1424         MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1425 }
1426
1427 static void VM_SV_WriteChar(prvm_prog_t *prog)
1428 {
1429         VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1430         MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1431 }
1432
1433 static void VM_SV_WriteShort(prvm_prog_t *prog)
1434 {
1435         VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1436         MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1437 }
1438
1439 static void VM_SV_WriteLong(prvm_prog_t *prog)
1440 {
1441         VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1442         MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1443 }
1444
1445 static void VM_SV_WriteAngle(prvm_prog_t *prog)
1446 {
1447         VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1448         MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1449 }
1450
1451 static void VM_SV_WriteCoord(prvm_prog_t *prog)
1452 {
1453         VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1454         MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1455 }
1456
1457 static void VM_SV_WriteString(prvm_prog_t *prog)
1458 {
1459         VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1460         MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1461 }
1462
1463 static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
1464 {
1465         VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1466         MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1467 }
1468
1469
1470 static void VM_SV_WriteEntity(prvm_prog_t *prog)
1471 {
1472         VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1473         MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
1474 }
1475
1476 // writes a picture as at most size bytes of data
1477 // message:
1478 //   IMGNAME \0 SIZE(short) IMGDATA
1479 // if failed to read/compress:
1480 //   IMGNAME \0 \0 \0
1481 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1482 static void VM_SV_WritePicture(prvm_prog_t *prog)
1483 {
1484         const char *imgname;
1485         void *buf;
1486         size_t size;
1487
1488         VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1489
1490         imgname = PRVM_G_STRING(OFS_PARM1);
1491         size = (int) PRVM_G_FLOAT(OFS_PARM2);
1492         if(size > 65535)
1493                 size = 65535;
1494
1495         MSG_WriteString(WriteDest(prog), imgname);
1496         if(Image_Compress(imgname, size, &buf, &size))
1497         {
1498                 // actual picture
1499                 MSG_WriteShort(WriteDest(prog), size);
1500                 SZ_Write(WriteDest(prog), (unsigned char *) buf, size);
1501         }
1502         else
1503         {
1504                 // placeholder
1505                 MSG_WriteShort(WriteDest(prog), 0);
1506         }
1507 }
1508
1509 //////////////////////////////////////////////////////////
1510
1511 static void VM_SV_makestatic(prvm_prog_t *prog)
1512 {
1513         prvm_edict_t *ent;
1514         int i, large;
1515
1516         // allow 0 parameters due to an id1 qc bug in which this function is used
1517         // with no parameters (but directly after setmodel with self in OFS_PARM0)
1518         VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1519
1520         if (prog->argc >= 1)
1521                 ent = PRVM_G_EDICT(OFS_PARM0);
1522         else
1523                 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1524         if (ent == prog->edicts)
1525         {
1526                 VM_Warning(prog, "makestatic: can not modify world entity\n");
1527                 return;
1528         }
1529         if (ent->priv.server->free)
1530         {
1531                 VM_Warning(prog, "makestatic: can not modify free entity\n");
1532                 return;
1533         }
1534
1535         large = false;
1536         if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
1537                 large = true;
1538
1539         if (large)
1540         {
1541                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1542                 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1543                 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1544         }
1545         else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1546         {
1547                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1548                 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1549                 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1550         }
1551         else
1552         {
1553                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1554                 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1555                 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1556         }
1557
1558         MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
1559         MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
1560         for (i=0 ; i<3 ; i++)
1561         {
1562                 MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
1563                 MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
1564         }
1565
1566 // throw the entity away now
1567         PRVM_ED_Free(prog, ent);
1568 }
1569
1570 //=============================================================================
1571
1572 /*
1573 ==============
1574 VM_SV_setspawnparms
1575 ==============
1576 */
1577 static void VM_SV_setspawnparms(prvm_prog_t *prog)
1578 {
1579         prvm_edict_t    *ent;
1580         int             i;
1581         client_t        *client;
1582
1583         VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1584
1585         ent = PRVM_G_EDICT(OFS_PARM0);
1586         i = PRVM_NUM_FOR_EDICT(ent);
1587         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1588         {
1589                 Con_Print("tried to setspawnparms on a non-client\n");
1590                 return;
1591         }
1592
1593         // copy spawn parms out of the client_t
1594         client = svs.clients + i-1;
1595         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1596                 (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
1597 }
1598
1599 /*
1600 =================
1601 VM_SV_getlight
1602
1603 Returns a color vector indicating the lighting at the requested point.
1604
1605 (Internal Operation note: actually measures the light beneath the point, just like
1606                           the model lighting on the client)
1607
1608 getlight(vector)
1609 =================
1610 */
1611 static void VM_SV_getlight(prvm_prog_t *prog)
1612 {
1613         vec3_t ambientcolor, diffusecolor, diffusenormal;
1614         vec3_t p;
1615         VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1616         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
1617         VectorClear(ambientcolor);
1618         VectorClear(diffusecolor);
1619         VectorClear(diffusenormal);
1620         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1621                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1622         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1623 }
1624
1625 typedef struct
1626 {
1627         unsigned char   type;   // 1/2/8 or other value if isn't used
1628         int             fieldoffset;
1629 }customstat_t;
1630
1631 static customstat_t *vm_customstats = NULL;     //[515]: it starts from 0, not 32
1632 static int vm_customstats_last;
1633
1634 void VM_CustomStats_Clear (void)
1635 {
1636         if(vm_customstats)
1637         {
1638                 Z_Free(vm_customstats);
1639                 vm_customstats = NULL;
1640                 vm_customstats_last = -1;
1641         }
1642 }
1643
1644 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1645 {
1646         prvm_prog_t *prog = SVVM_prog;
1647         int                     i;
1648         char            s[17];
1649
1650         if(!vm_customstats)
1651                 return;
1652
1653         for(i=0; i<vm_customstats_last+1 ;i++)
1654         {
1655                 if(!vm_customstats[i].type)
1656                         continue;
1657                 switch(vm_customstats[i].type)
1658                 {
1659                 //string as 16 bytes
1660                 case 1:
1661                         memset(s, 0, 17);
1662                         strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1663                         stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1664                         stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1665                         stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1666                         stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1667                         break;
1668                 //float field sent as-is
1669                 case 8:
1670                         stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1671                         break;
1672                 //integer value of float field
1673                 case 2:
1674                         stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1675                         break;
1676                 default:
1677                         break;
1678                 }
1679         }
1680 }
1681
1682 // void(float index, float type, .void field) SV_AddStat = #232;
1683 // Set up an auto-sent player stat.
1684 // Client's get thier own fields sent to them. Index may not be less than 32.
1685 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1686 //          1: string (4 stats carrying a total of 16 charactures)
1687 //          2: float (one stat, float converted to an integer for transportation)
1688 //          8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1689 static void VM_SV_AddStat(prvm_prog_t *prog)
1690 {
1691         int             off, i;
1692         unsigned char   type;
1693
1694         VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1695
1696         if(!vm_customstats)
1697         {
1698                 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1699                 if(!vm_customstats)
1700                 {
1701                         VM_Warning(prog, "PF_SV_AddStat: not enough memory\n");
1702                         return;
1703                 }
1704         }
1705         i               = (int)PRVM_G_FLOAT(OFS_PARM0);
1706         type    = (int)PRVM_G_FLOAT(OFS_PARM1);
1707         off             = PRVM_G_INT  (OFS_PARM2);
1708         i -= 32;
1709
1710         if(i < 0)
1711         {
1712                 VM_Warning(prog, "PF_SV_AddStat: index may not be less than 32\n");
1713                 return;
1714         }
1715         if(i >= (MAX_CL_STATS-32))
1716         {
1717                 VM_Warning(prog, "PF_SV_AddStat: index >= MAX_CL_STATS\n");
1718                 return;
1719         }
1720         if(i > (MAX_CL_STATS-32-4) && type == 1)
1721         {
1722                 VM_Warning(prog, "PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1723                 return;
1724         }
1725         vm_customstats[i].type          = type;
1726         vm_customstats[i].fieldoffset   = off;
1727         if(vm_customstats_last < i)
1728                 vm_customstats_last = i;
1729 }
1730
1731 /*
1732 =================
1733 VM_SV_copyentity
1734
1735 copies data from one entity to another
1736
1737 copyentity(src, dst)
1738 =================
1739 */
1740 static void VM_SV_copyentity(prvm_prog_t *prog)
1741 {
1742         prvm_edict_t *in, *out;
1743         VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1744         in = PRVM_G_EDICT(OFS_PARM0);
1745         if (in == prog->edicts)
1746         {
1747                 VM_Warning(prog, "copyentity: can not read world entity\n");
1748                 return;
1749         }
1750         if (in->priv.server->free)
1751         {
1752                 VM_Warning(prog, "copyentity: can not read free entity\n");
1753                 return;
1754         }
1755         out = PRVM_G_EDICT(OFS_PARM1);
1756         if (out == prog->edicts)
1757         {
1758                 VM_Warning(prog, "copyentity: can not modify world entity\n");
1759                 return;
1760         }
1761         if (out->priv.server->free)
1762         {
1763                 VM_Warning(prog, "copyentity: can not modify free entity\n");
1764                 return;
1765         }
1766         memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
1767         SV_LinkEdict(out);
1768 }
1769
1770
1771 /*
1772 =================
1773 VM_SV_setcolor
1774
1775 sets the color of a client and broadcasts the update to all connected clients
1776
1777 setcolor(clientent, value)
1778 =================
1779 */
1780 static void VM_SV_setcolor(prvm_prog_t *prog)
1781 {
1782         client_t *client;
1783         int entnum, i;
1784
1785         VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1786         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1787         i = (int)PRVM_G_FLOAT(OFS_PARM1);
1788
1789         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1790         {
1791                 Con_Print("tried to setcolor a non-client\n");
1792                 return;
1793         }
1794
1795         client = svs.clients + entnum-1;
1796         if (client->edict)
1797         {
1798                 PRVM_serveredictfloat(client->edict, clientcolors) = i;
1799                 PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
1800         }
1801         client->colors = i;
1802         if (client->old_colors != client->colors)
1803         {
1804                 client->old_colors = client->colors;
1805                 // send notification to all clients
1806                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1807                 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1808                 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1809         }
1810 }
1811
1812 /*
1813 =================
1814 VM_SV_effect
1815
1816 effect(origin, modelname, startframe, framecount, framerate)
1817 =================
1818 */
1819 static void VM_SV_effect(prvm_prog_t *prog)
1820 {
1821         int i;
1822         const char *s;
1823         vec3_t org;
1824         VM_SAFEPARMCOUNT(5, VM_SV_effect);
1825         s = PRVM_G_STRING(OFS_PARM1);
1826         if (!s[0])
1827         {
1828                 VM_Warning(prog, "effect: no model specified\n");
1829                 return;
1830         }
1831
1832         i = SV_ModelIndex(s, 1);
1833         if (!i)
1834         {
1835                 VM_Warning(prog, "effect: model not precached\n");
1836                 return;
1837         }
1838
1839         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1840         {
1841                 VM_Warning(prog, "effect: framecount < 1\n");
1842                 return;
1843         }
1844
1845         if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1846         {
1847                 VM_Warning(prog, "effect: framerate < 1\n");
1848                 return;
1849         }
1850
1851         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1852         SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1853 }
1854
1855 static void VM_SV_te_blood(prvm_prog_t *prog)
1856 {
1857         VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1858         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1859                 return;
1860         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1861         MSG_WriteByte(&sv.datagram, TE_BLOOD);
1862         // origin
1863         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1864         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1865         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1866         // velocity
1867         MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1868         MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1869         MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1870         // count
1871         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1872         SV_FlushBroadcastMessages();
1873 }
1874
1875 static void VM_SV_te_bloodshower(prvm_prog_t *prog)
1876 {
1877         VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1878         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1879                 return;
1880         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1881         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1882         // min
1883         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1884         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1885         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1886         // max
1887         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1888         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1889         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1890         // speed
1891         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1892         // count
1893         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1894         SV_FlushBroadcastMessages();
1895 }
1896
1897 static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
1898 {
1899         VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1900         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1901         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1902         // origin
1903         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1904         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1905         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1906         // color
1907         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1908         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1909         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1910         SV_FlushBroadcastMessages();
1911 }
1912
1913 static void VM_SV_te_particlecube(prvm_prog_t *prog)
1914 {
1915         VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1916         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1917                 return;
1918         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1919         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1920         // min
1921         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1922         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1923         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1924         // max
1925         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1926         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1927         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1928         // velocity
1929         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1930         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1931         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1932         // count
1933         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1934         // color
1935         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1936         // gravity true/false
1937         MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1938         // randomvel
1939         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1940         SV_FlushBroadcastMessages();
1941 }
1942
1943 static void VM_SV_te_particlerain(prvm_prog_t *prog)
1944 {
1945         VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1946         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1947                 return;
1948         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1949         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1950         // min
1951         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1952         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1953         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1954         // max
1955         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1956         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1957         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1958         // velocity
1959         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1960         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1961         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1962         // count
1963         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1964         // color
1965         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1966         SV_FlushBroadcastMessages();
1967 }
1968
1969 static void VM_SV_te_particlesnow(prvm_prog_t *prog)
1970 {
1971         VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1972         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1973                 return;
1974         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1975         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1976         // min
1977         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1978         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1979         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1980         // max
1981         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1982         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1983         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1984         // velocity
1985         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1986         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1987         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1988         // count
1989         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1990         // color
1991         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1992         SV_FlushBroadcastMessages();
1993 }
1994
1995 static void VM_SV_te_spark(prvm_prog_t *prog)
1996 {
1997         VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1998         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1999                 return;
2000         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2001         MSG_WriteByte(&sv.datagram, TE_SPARK);
2002         // origin
2003         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2004         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2005         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2006         // velocity
2007         MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2008         MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2009         MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2010         // count
2011         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2012         SV_FlushBroadcastMessages();
2013 }
2014
2015 static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
2016 {
2017         VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
2018         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2019         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2020         // origin
2021         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2022         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2023         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2024         SV_FlushBroadcastMessages();
2025 }
2026
2027 static void VM_SV_te_spikequad(prvm_prog_t *prog)
2028 {
2029         VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2030         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2031         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2032         // origin
2033         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2034         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2035         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2036         SV_FlushBroadcastMessages();
2037 }
2038
2039 static void VM_SV_te_superspikequad(prvm_prog_t *prog)
2040 {
2041         VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2042         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2043         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2044         // origin
2045         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2046         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2047         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2048         SV_FlushBroadcastMessages();
2049 }
2050
2051 static void VM_SV_te_explosionquad(prvm_prog_t *prog)
2052 {
2053         VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2054         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2055         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2056         // origin
2057         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2058         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2059         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2060         SV_FlushBroadcastMessages();
2061 }
2062
2063 static void VM_SV_te_smallflash(prvm_prog_t *prog)
2064 {
2065         VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2066         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2067         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2068         // origin
2069         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2070         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2071         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2072         SV_FlushBroadcastMessages();
2073 }
2074
2075 static void VM_SV_te_customflash(prvm_prog_t *prog)
2076 {
2077         VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2078         if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2079                 return;
2080         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2081         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2082         // origin
2083         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2084         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2085         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2086         // radius
2087         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2088         // lifetime
2089         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2090         // color
2091         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2092         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2093         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2094         SV_FlushBroadcastMessages();
2095 }
2096
2097 static void VM_SV_te_gunshot(prvm_prog_t *prog)
2098 {
2099         VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2100         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2101         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2102         // origin
2103         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2104         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2105         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2106         SV_FlushBroadcastMessages();
2107 }
2108
2109 static void VM_SV_te_spike(prvm_prog_t *prog)
2110 {
2111         VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2112         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2113         MSG_WriteByte(&sv.datagram, TE_SPIKE);
2114         // origin
2115         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2116         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2117         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2118         SV_FlushBroadcastMessages();
2119 }
2120
2121 static void VM_SV_te_superspike(prvm_prog_t *prog)
2122 {
2123         VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2124         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2125         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2126         // origin
2127         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2128         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2129         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2130         SV_FlushBroadcastMessages();
2131 }
2132
2133 static void VM_SV_te_explosion(prvm_prog_t *prog)
2134 {
2135         VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2136         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2137         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2138         // origin
2139         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2140         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2141         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2142         SV_FlushBroadcastMessages();
2143 }
2144
2145 static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
2146 {
2147         VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2148         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2149         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2150         // origin
2151         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2152         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2153         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2154         SV_FlushBroadcastMessages();
2155 }
2156
2157 static void VM_SV_te_wizspike(prvm_prog_t *prog)
2158 {
2159         VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2160         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2161         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2162         // origin
2163         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2164         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2165         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2166         SV_FlushBroadcastMessages();
2167 }
2168
2169 static void VM_SV_te_knightspike(prvm_prog_t *prog)
2170 {
2171         VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2172         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2173         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2174         // origin
2175         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2176         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2177         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2178         SV_FlushBroadcastMessages();
2179 }
2180
2181 static void VM_SV_te_lavasplash(prvm_prog_t *prog)
2182 {
2183         VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2184         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2185         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2186         // origin
2187         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2188         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2189         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2190         SV_FlushBroadcastMessages();
2191 }
2192
2193 static void VM_SV_te_teleport(prvm_prog_t *prog)
2194 {
2195         VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2196         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2197         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2198         // origin
2199         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2200         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2201         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2202         SV_FlushBroadcastMessages();
2203 }
2204
2205 static void VM_SV_te_explosion2(prvm_prog_t *prog)
2206 {
2207         VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2208         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2209         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2210         // origin
2211         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2212         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2213         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2214         // color
2215         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2216         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2217         SV_FlushBroadcastMessages();
2218 }
2219
2220 static void VM_SV_te_lightning1(prvm_prog_t *prog)
2221 {
2222         VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2223         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2224         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2225         // owner entity
2226         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2227         // start
2228         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2229         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2230         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2231         // end
2232         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2233         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2234         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2235         SV_FlushBroadcastMessages();
2236 }
2237
2238 static void VM_SV_te_lightning2(prvm_prog_t *prog)
2239 {
2240         VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2241         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2242         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2243         // owner entity
2244         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2245         // start
2246         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2247         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2248         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2249         // end
2250         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2251         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2252         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2253         SV_FlushBroadcastMessages();
2254 }
2255
2256 static void VM_SV_te_lightning3(prvm_prog_t *prog)
2257 {
2258         VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2259         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2260         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2261         // owner entity
2262         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2263         // start
2264         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2265         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2266         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2267         // end
2268         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2269         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2270         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2271         SV_FlushBroadcastMessages();
2272 }
2273
2274 static void VM_SV_te_beam(prvm_prog_t *prog)
2275 {
2276         VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2277         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278         MSG_WriteByte(&sv.datagram, TE_BEAM);
2279         // owner entity
2280         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2281         // start
2282         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2283         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2284         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2285         // end
2286         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2287         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2288         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2289         SV_FlushBroadcastMessages();
2290 }
2291
2292 static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
2293 {
2294         VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2295         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2296         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2297         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2298         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2299         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2300         SV_FlushBroadcastMessages();
2301 }
2302
2303 static void VM_SV_te_flamejet(prvm_prog_t *prog)
2304 {
2305         VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2306         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2307         MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2308         // org
2309         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2310         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2311         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2312         // vel
2313         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2314         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2315         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2316         // count
2317         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2318         SV_FlushBroadcastMessages();
2319 }
2320
2321 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2322 //this function originally written by KrimZon, made shorter by LordHavoc
2323 static void VM_SV_clientcommand(prvm_prog_t *prog)
2324 {
2325         client_t *temp_client;
2326         int i;
2327         VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2328
2329         //find client for this entity
2330         i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2331         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2332         {
2333                 Con_Print("PF_clientcommand: entity is not a client\n");
2334                 return;
2335         }
2336
2337         temp_client = host_client;
2338         host_client = svs.clients + i;
2339         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client, true);
2340         host_client = temp_client;
2341 }
2342
2343 //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)
2344 static void VM_SV_setattachment(prvm_prog_t *prog)
2345 {
2346         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2347         prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2348         const char *tagname = PRVM_G_STRING(OFS_PARM2);
2349         dp_model_t *model;
2350         int tagindex;
2351         VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2352
2353         if (e == prog->edicts)
2354         {
2355                 VM_Warning(prog, "setattachment: can not modify world entity\n");
2356                 return;
2357         }
2358         if (e->priv.server->free)
2359         {
2360                 VM_Warning(prog, "setattachment: can not modify free entity\n");
2361                 return;
2362         }
2363
2364         if (tagentity == NULL)
2365                 tagentity = prog->edicts;
2366
2367         tagindex = 0;
2368
2369         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2370         {
2371                 model = SV_GetModelFromEdict(tagentity);
2372                 if (model)
2373                 {
2374                         tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
2375                         if (tagindex == 0)
2376                                 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);
2377                 }
2378                 else
2379                         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));
2380         }
2381
2382         PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
2383         PRVM_serveredictfloat(e, tag_index) = tagindex;
2384 }
2385
2386 /////////////////////////////////////////
2387 // DP_MD3_TAGINFO extension coded by VorteX
2388
2389 static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
2390 {
2391         int i;
2392
2393         i = (int)PRVM_serveredictfloat(e, modelindex);
2394         if (i < 1 || i >= MAX_MODELS)
2395                 return -1;
2396
2397         return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
2398 }
2399
2400 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2401 {
2402         int r;
2403         dp_model_t *model;
2404
2405         *tagname = NULL;
2406         *parentindex = 0;
2407         Matrix4x4_CreateIdentity(tag_localmatrix);
2408
2409         if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2410         {
2411                 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2412
2413                 if(!r) // success?
2414                         *parentindex += 1;
2415
2416                 return r;
2417         }
2418
2419         return 1;
2420 }
2421
2422 void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2423 {
2424         float scale;
2425         float pitchsign = 1;
2426
2427         scale = PRVM_serveredictfloat(ent, scale);
2428         if (!scale)
2429                 scale = 1.0f;
2430         
2431         if (viewmatrix)
2432                 Matrix4x4_CreateFromQuakeEntity(out, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2], PRVM_serveredictvector(ent, v_angle)[0], PRVM_serveredictvector(ent, v_angle)[1], PRVM_serveredictvector(ent, v_angle)[2], scale * cl_viewmodel_scale.value);
2433         else
2434         {
2435                 pitchsign = SV_GetPitchSign(prog, ent);
2436                 Matrix4x4_CreateFromQuakeEntity(out, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], pitchsign * PRVM_serveredictvector(ent, angles)[0], PRVM_serveredictvector(ent, angles)[1], PRVM_serveredictvector(ent, angles)[2], scale);
2437         }
2438 }
2439
2440 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2441 {
2442         dp_model_t *model;
2443         if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2444         {
2445                 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2446                 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2447                 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2448                 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2449         }
2450         *out = identitymatrix;
2451         return 0;
2452 }
2453
2454 // Warnings/errors code:
2455 // 0 - normal (everything all-right)
2456 // 1 - world entity
2457 // 2 - free entity
2458 // 3 - null or non-precached model
2459 // 4 - no tags with requested index
2460 // 5 - runaway loop at attachment chain
2461 extern cvar_t cl_bob;
2462 extern cvar_t cl_bobcycle;
2463 extern cvar_t cl_bobup;
2464 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2465 {
2466         int ret;
2467         int modelindex, attachloop;
2468         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2469         dp_model_t *model;
2470
2471         *out = identitymatrix; // warnings and errors return identical matrix
2472
2473         if (ent == prog->edicts)
2474                 return 1;
2475         if (ent->priv.server->free)
2476                 return 2;
2477
2478         modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
2479         if (modelindex <= 0 || modelindex >= MAX_MODELS)
2480                 return 3;
2481
2482         model = SV_GetModelByIndex(modelindex);
2483
2484         VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2485         VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2486         VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2487
2488         tagmatrix = identitymatrix;
2489         // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2490         attachloop = 0;
2491         for (;;)
2492         {
2493                 if (attachloop >= 256) // prevent runaway looping
2494                         return 5;
2495                 // apply transformation by child's tagindex on parent entity and then
2496                 // by parent entity itself
2497                 ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
2498                 if (ret && attachloop == 0)
2499                         return ret;
2500                 SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
2501                 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2502                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2503                 // next iteration we process the parent entity
2504                 if (PRVM_serveredictedict(ent, tag_entity))
2505                 {
2506                         tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
2507                         ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
2508                 }
2509                 else
2510                         break;
2511                 attachloop++;
2512         }
2513
2514         // RENDER_VIEWMODEL magic
2515         if (PRVM_serveredictedict(ent, viewmodelforclient))
2516         {
2517                 Matrix4x4_Copy(&tagmatrix, out);
2518                 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
2519
2520                 SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
2521                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2522
2523                 /*
2524                 // Cl_bob, ported from rendering code
2525                 if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
2526                 {
2527                         double bob, cycle;
2528                         // LordHavoc: this code is *weird*, but not replacable (I think it
2529                         // should be done in QC on the server, but oh well, quake is quake)
2530                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2531                         // degrees (which allows lengthening or squishing the peak or valley)
2532                         cycle = sv.time/cl_bobcycle.value;
2533                         cycle -= (int)cycle;
2534                         if (cycle < cl_bobup.value)
2535                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2536                         else
2537                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2538                         // bob is proportional to velocity in the xy plane
2539                         // (don't count Z, or jumping messes it up)
2540                         bob = sqrt(PRVM_serveredictvector(ent, velocity)[0]*PRVM_serveredictvector(ent, velocity)[0] + PRVM_serveredictvector(ent, velocity)[1]*PRVM_serveredictvector(ent, velocity)[1])*cl_bob.value;
2541                         bob = bob*0.3 + bob*0.7*cycle;
2542                         Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2543                 }
2544                 */
2545         }
2546         return 0;
2547 }
2548
2549 //float(entity ent, string tagname) gettagindex;
2550
2551 static void VM_SV_gettagindex(prvm_prog_t *prog)
2552 {
2553         prvm_edict_t *ent;
2554         const char *tag_name;
2555         int tag_index;
2556
2557         VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2558
2559         ent = PRVM_G_EDICT(OFS_PARM0);
2560         tag_name = PRVM_G_STRING(OFS_PARM1);
2561
2562         if (ent == prog->edicts)
2563         {
2564                 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2565                 return;
2566         }
2567         if (ent->priv.server->free)
2568         {
2569                 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2570                 return;
2571         }
2572
2573         tag_index = 0;
2574         if (!SV_GetModelFromEdict(ent))
2575                 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2576         else
2577         {
2578                 tag_index = SV_GetTagIndex(prog, ent, tag_name);
2579                 if (tag_index == 0)
2580                         if(developer_extra.integer)
2581                                 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2582         }
2583         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2584 }
2585
2586 //vector(entity ent, float tagindex) gettaginfo;
2587 static void VM_SV_gettaginfo(prvm_prog_t *prog)
2588 {
2589         prvm_edict_t *e;
2590         int tagindex;
2591         matrix4x4_t tag_matrix;
2592         matrix4x4_t tag_localmatrix;
2593         int parentindex;
2594         const char *tagname;
2595         int returncode;
2596         vec3_t forward, left, up, origin;
2597         const dp_model_t *model;
2598
2599         VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2600
2601         e = PRVM_G_EDICT(OFS_PARM0);
2602         tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2603
2604         returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
2605         Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
2606         VectorCopy(forward, PRVM_serverglobalvector(v_forward));
2607         VectorNegate(left, PRVM_serverglobalvector(v_right));
2608         VectorCopy(up, PRVM_serverglobalvector(v_up));
2609         VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
2610         model = SV_GetModelFromEdict(e);
2611         VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
2612         VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
2613         VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
2614         SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2615         Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
2616
2617         PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
2618         PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
2619         VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
2620         VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
2621         VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
2622         VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
2623
2624         switch(returncode)
2625         {
2626                 case 1:
2627                         VM_Warning(prog, "gettagindex: can't affect world entity\n");
2628                         break;
2629                 case 2:
2630                         VM_Warning(prog, "gettagindex: can't affect free entity\n");
2631                         break;
2632                 case 3:
2633                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2634                         break;
2635                 case 4:
2636                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2637                         break;
2638                 case 5:
2639                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2640                         break;
2641         }
2642 }
2643
2644 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2645 static void VM_SV_dropclient(prvm_prog_t *prog)
2646 {
2647         int clientnum;
2648         client_t *oldhostclient;
2649         VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2650         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2651         if (clientnum < 0 || clientnum >= svs.maxclients)
2652         {
2653                 VM_Warning(prog, "dropclient: not a client\n");
2654                 return;
2655         }
2656         if (!svs.clients[clientnum].active)
2657         {
2658                 VM_Warning(prog, "dropclient: that client slot is not connected\n");
2659                 return;
2660         }
2661         oldhostclient = host_client;
2662         host_client = svs.clients + clientnum;
2663         SV_DropClient(false);
2664         host_client = oldhostclient;
2665 }
2666
2667 //entity() spawnclient (DP_SV_BOTCLIENT)
2668 static void VM_SV_spawnclient(prvm_prog_t *prog)
2669 {
2670         int i;
2671         prvm_edict_t    *ed;
2672         VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2673         prog->xfunction->builtinsprofile += 2;
2674         ed = prog->edicts;
2675         for (i = 0;i < svs.maxclients;i++)
2676         {
2677                 if (!svs.clients[i].active)
2678                 {
2679                         prog->xfunction->builtinsprofile += 100;
2680                         SV_ConnectClient (i, NULL);
2681                         // this has to be set or else ClientDisconnect won't be called
2682                         // we assume the qc will call ClientConnect...
2683                         svs.clients[i].clientconnectcalled = true;
2684                         ed = PRVM_EDICT_NUM(i + 1);
2685                         break;
2686                 }
2687         }
2688         VM_RETURN_EDICT(ed);
2689 }
2690
2691 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2692 static void VM_SV_clienttype(prvm_prog_t *prog)
2693 {
2694         int clientnum;
2695         VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2696         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2697         if (clientnum < 0 || clientnum >= svs.maxclients)
2698                 PRVM_G_FLOAT(OFS_RETURN) = 3;
2699         else if (!svs.clients[clientnum].active)
2700                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2701         else if (svs.clients[clientnum].netconnection)
2702                 PRVM_G_FLOAT(OFS_RETURN) = 1;
2703         else
2704                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2705 }
2706
2707 /*
2708 ===============
2709 VM_SV_serverkey
2710
2711 string(string key) serverkey
2712 ===============
2713 */
2714 static void VM_SV_serverkey(prvm_prog_t *prog)
2715 {
2716         char string[VM_STRINGTEMP_LENGTH];
2717         VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2718         InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2719         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2720 }
2721
2722 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2723 static void VM_SV_setmodelindex(prvm_prog_t *prog)
2724 {
2725         prvm_edict_t    *e;
2726         dp_model_t      *mod;
2727         int             i;
2728         VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2729
2730         e = PRVM_G_EDICT(OFS_PARM0);
2731         if (e == prog->edicts)
2732         {
2733                 VM_Warning(prog, "setmodelindex: can not modify world entity\n");
2734                 return;
2735         }
2736         if (e->priv.server->free)
2737         {
2738                 VM_Warning(prog, "setmodelindex: can not modify free entity\n");
2739                 return;
2740         }
2741         i = (int)PRVM_G_FLOAT(OFS_PARM1);
2742         if (i <= 0 || i >= MAX_MODELS)
2743         {
2744                 VM_Warning(prog, "setmodelindex: invalid modelindex\n");
2745                 return;
2746         }
2747         if (!sv.model_precache[i][0])
2748         {
2749                 VM_Warning(prog, "setmodelindex: model not precached\n");
2750                 return;
2751         }
2752
2753         PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2754         PRVM_serveredictfloat(e, modelindex) = i;
2755
2756         mod = SV_GetModelByIndex(i);
2757
2758         if (mod)
2759         {
2760                 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2761                         SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
2762                 else
2763                         SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
2764         }
2765         else
2766                 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
2767 }
2768
2769 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2770 static void VM_SV_modelnameforindex(prvm_prog_t *prog)
2771 {
2772         int i;
2773         VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2774
2775         PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2776
2777         i = (int)PRVM_G_FLOAT(OFS_PARM0);
2778         if (i <= 0 || i >= MAX_MODELS)
2779         {
2780                 VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
2781                 return;
2782         }
2783         if (!sv.model_precache[i][0])
2784         {
2785                 VM_Warning(prog, "modelnameforindex: model not precached\n");
2786                 return;
2787         }
2788
2789         PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2790 }
2791
2792 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2793 static void VM_SV_particleeffectnum(prvm_prog_t *prog)
2794 {
2795         int                     i;
2796         VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2797         i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2798         if (i == 0)
2799                 i = -1;
2800         PRVM_G_FLOAT(OFS_RETURN) = i;
2801 }
2802
2803 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2804 static void VM_SV_trailparticles(prvm_prog_t *prog)
2805 {
2806         vec3_t start, end;
2807         VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2808
2809         if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2810                 return;
2811
2812         MSG_WriteByte(&sv.datagram, svc_trailparticles);
2813         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2814         MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2815         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2816         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2817         MSG_WriteVector(&sv.datagram, start, sv.protocol);
2818         MSG_WriteVector(&sv.datagram, end, sv.protocol);
2819         SV_FlushBroadcastMessages();
2820 }
2821
2822 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
2823 static void VM_SV_pointparticles(prvm_prog_t *prog)
2824 {
2825         int effectnum, count;
2826         vec3_t org, vel;
2827         VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
2828
2829         if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2830                 return;
2831
2832         effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2833         VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
2834         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2835         count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
2836         if (count == 1 && !VectorLength2(vel))
2837         {
2838                 // 1+2+12=15 bytes
2839                 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
2840                 MSG_WriteShort(&sv.datagram, effectnum);
2841                 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2842         }
2843         else
2844         {
2845                 // 1+2+12+12+2=29 bytes
2846                 MSG_WriteByte(&sv.datagram, svc_pointparticles);
2847                 MSG_WriteShort(&sv.datagram, effectnum);
2848                 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2849                 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
2850                 MSG_WriteShort(&sv.datagram, count);
2851         }
2852
2853         SV_FlushBroadcastMessages();
2854 }
2855
2856 //PF_setpause,    // void(float pause) setpause = #531;
2857 static void VM_SV_setpause(prvm_prog_t *prog) {
2858         int pauseValue;
2859         pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
2860         if (pauseValue != 0) { //pause the game
2861                 sv.paused = 1;
2862                 sv.pausedstart = realtime;
2863         } else { //disable pause, in case it was enabled
2864                 if (sv.paused != 0) {
2865                         sv.paused = 0;
2866                         sv.pausedstart = 0;
2867                 }
2868         }
2869         // send notification to all clients
2870         MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
2871         MSG_WriteByte(&sv.reliable_datagram, sv.paused);
2872 }
2873
2874 // #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure  (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex.
2875 static void VM_SV_skel_create(prvm_prog_t *prog)
2876 {
2877         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
2878         dp_model_t *model = SV_GetModelByIndex(modelindex);
2879         skeleton_t *skeleton;
2880         int i;
2881         PRVM_G_FLOAT(OFS_RETURN) = 0;
2882         if (!model || !model->num_bones)
2883                 return;
2884         for (i = 0;i < MAX_EDICTS;i++)
2885                 if (!prog->skeletons[i])
2886                         break;
2887         if (i == MAX_EDICTS)
2888                 return;
2889         prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
2890         PRVM_G_FLOAT(OFS_RETURN) = i + 1;
2891         skeleton->model = model;
2892         skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
2893         // initialize to identity matrices
2894         for (i = 0;i < skeleton->model->num_bones;i++)
2895                 skeleton->relativetransforms[i] = identitymatrix;
2896 }
2897
2898 // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
2899 static void VM_SV_skel_build(prvm_prog_t *prog)
2900 {
2901         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2902         skeleton_t *skeleton;
2903         prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
2904         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
2905         float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
2906         int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
2907         int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
2908         dp_model_t *model = SV_GetModelByIndex(modelindex);
2909         float blendfrac;
2910         int numblends;
2911         int bonenum;
2912         int blendindex;
2913         framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
2914         frameblend_t frameblend[MAX_FRAMEBLENDS];
2915         matrix4x4_t blendedmatrix;
2916         matrix4x4_t matrix;
2917         PRVM_G_FLOAT(OFS_RETURN) = 0;
2918         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2919                 return;
2920         firstbone = max(0, firstbone);
2921         lastbone = min(lastbone, model->num_bones - 1);
2922         lastbone = min(lastbone, skeleton->model->num_bones - 1);
2923         VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
2924         VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
2925         blendfrac = 1.0f - retainfrac;
2926         for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
2927                 frameblend[numblends].lerp *= blendfrac;
2928         for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
2929         {
2930                 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
2931                 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
2932                 for (blendindex = 0;blendindex < numblends;blendindex++)
2933                 {
2934                         Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
2935                         Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
2936                 }
2937                 skeleton->relativetransforms[bonenum] = blendedmatrix;
2938         }
2939         PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
2940 }
2941
2942 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
2943 static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
2944 {
2945         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2946         skeleton_t *skeleton;
2947         PRVM_G_FLOAT(OFS_RETURN) = 0;
2948         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2949                 return;
2950         PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
2951 }
2952
2953 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
2954 static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
2955 {
2956         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2957         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2958         skeleton_t *skeleton;
2959         PRVM_G_INT(OFS_RETURN) = 0;
2960         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2961                 return;
2962         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2963                 return;
2964         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
2965 }
2966
2967 // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
2968 static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
2969 {
2970         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2971         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2972         skeleton_t *skeleton;
2973         PRVM_G_FLOAT(OFS_RETURN) = 0;
2974         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2975                 return;
2976         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2977                 return;
2978         PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
2979 }
2980
2981 // #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
2982 static void VM_SV_skel_find_bone(prvm_prog_t *prog)
2983 {
2984         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2985         const char *tagname = PRVM_G_STRING(OFS_PARM1);
2986         skeleton_t *skeleton;
2987         PRVM_G_FLOAT(OFS_RETURN) = 0;
2988         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2989                 return;
2990         PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
2991 }
2992
2993 // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
2994 static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
2995 {
2996         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2997         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2998         skeleton_t *skeleton;
2999         matrix4x4_t matrix;
3000         vec3_t forward, left, up, origin;
3001         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3002         VectorClear(PRVM_clientglobalvector(v_forward));
3003         VectorClear(PRVM_clientglobalvector(v_right));
3004         VectorClear(PRVM_clientglobalvector(v_up));
3005         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3006                 return;
3007         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3008                 return;
3009         matrix = skeleton->relativetransforms[bonenum];
3010         Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3011         VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3012         VectorNegate(left, PRVM_clientglobalvector(v_right));
3013         VectorCopy(up, PRVM_clientglobalvector(v_up));
3014         VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3015 }
3016
3017 // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
3018 static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
3019 {
3020         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3021         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3022         skeleton_t *skeleton;
3023         matrix4x4_t matrix;
3024         matrix4x4_t temp;
3025         vec3_t forward, left, up, origin;
3026         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3027         VectorClear(PRVM_clientglobalvector(v_forward));
3028         VectorClear(PRVM_clientglobalvector(v_right));
3029         VectorClear(PRVM_clientglobalvector(v_up));
3030         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3031                 return;
3032         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3033                 return;
3034         matrix = skeleton->relativetransforms[bonenum];
3035         // convert to absolute
3036         while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3037         {
3038                 temp = matrix;
3039                 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3040         }
3041         Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3042         VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3043         VectorNegate(left, PRVM_clientglobalvector(v_right));
3044         VectorCopy(up, PRVM_clientglobalvector(v_up));
3045         VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3046 }
3047
3048 // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
3049 static void VM_SV_skel_set_bone(prvm_prog_t *prog)
3050 {
3051         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3052         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3053         vec3_t forward, left, up, origin;
3054         skeleton_t *skeleton;
3055         matrix4x4_t matrix;
3056         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3057                 return;
3058         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3059                 return;
3060         VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3061         VectorNegate(PRVM_clientglobalvector(v_right), left);
3062         VectorCopy(PRVM_clientglobalvector(v_up), up);
3063         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3064         Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3065         skeleton->relativetransforms[bonenum] = matrix;
3066 }
3067
3068 // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
3069 static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
3070 {
3071         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3072         int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3073         vec3_t forward, left, up, origin;
3074         skeleton_t *skeleton;
3075         matrix4x4_t matrix;
3076         matrix4x4_t temp;
3077         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3078                 return;
3079         if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3080                 return;
3081         VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3082         VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3083         VectorNegate(PRVM_clientglobalvector(v_right), left);
3084         VectorCopy(PRVM_clientglobalvector(v_up), up);
3085         Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3086         temp = skeleton->relativetransforms[bonenum];
3087         Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3088 }
3089
3090 // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
3091 static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
3092 {
3093         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3094         int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3095         int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3096         int bonenum;
3097         vec3_t forward, left, up, origin;
3098         skeleton_t *skeleton;
3099         matrix4x4_t matrix;
3100         matrix4x4_t temp;
3101         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3102                 return;
3103         VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3104         VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3105         VectorNegate(PRVM_clientglobalvector(v_right), left);
3106         VectorCopy(PRVM_clientglobalvector(v_up), up);
3107         Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3108         firstbone = max(0, firstbone);
3109         lastbone = min(lastbone, skeleton->model->num_bones - 1);
3110         for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3111         {
3112                 temp = skeleton->relativetransforms[bonenum];
3113                 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3114         }
3115 }
3116
3117 // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
3118 static void VM_SV_skel_copybones(prvm_prog_t *prog)
3119 {
3120         int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3121         int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3122         int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3123         int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3124         int bonenum;
3125         skeleton_t *skeletondst;
3126         skeleton_t *skeletonsrc;
3127         if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3128                 return;
3129         if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3130                 return;
3131         firstbone = max(0, firstbone);
3132         lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3133         lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3134         for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3135                 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3136 }
3137
3138 // #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
3139 static void VM_SV_skel_delete(prvm_prog_t *prog)
3140 {
3141         int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3142         skeleton_t *skeleton;
3143         if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3144                 return;
3145         Mem_Free(skeleton);
3146         prog->skeletons[skeletonindex] = NULL;
3147 }
3148
3149 // #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found
3150 static void VM_SV_frameforname(prvm_prog_t *prog)
3151 {
3152         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3153         dp_model_t *model = SV_GetModelByIndex(modelindex);
3154         const char *name = PRVM_G_STRING(OFS_PARM1);
3155         int i;
3156         PRVM_G_FLOAT(OFS_RETURN) = -1;
3157         if (!model || !model->animscenes)
3158                 return;
3159         for (i = 0;i < model->numframes;i++)
3160         {
3161                 if (!strcasecmp(model->animscenes[i].name, name))
3162                 {
3163                         PRVM_G_FLOAT(OFS_RETURN) = i;
3164                         break;
3165                 }
3166         }
3167 }
3168
3169 // #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
3170 static void VM_SV_frameduration(prvm_prog_t *prog)
3171 {
3172         int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3173         dp_model_t *model = SV_GetModelByIndex(modelindex);
3174         int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3175         PRVM_G_FLOAT(OFS_RETURN) = 0;
3176         if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3177                 return;
3178         if (model->animscenes[framenum].framerate)
3179                 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3180 }
3181
3182
3183 prvm_builtin_t vm_sv_builtins[] = {
3184 NULL,                                                   // #0 NULL function (not callable) (QUAKE)
3185 VM_makevectors,                                 // #1 void(vector ang) makevectors (QUAKE)
3186 VM_SV_setorigin,                                // #2 void(entity e, vector o) setorigin (QUAKE)
3187 VM_SV_setmodel,                                 // #3 void(entity e, string m) setmodel (QUAKE)
3188 VM_SV_setsize,                                  // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3189 NULL,                                                   // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3190 VM_break,                                               // #6 void() break (QUAKE)
3191 VM_random,                                              // #7 float() random (QUAKE)
3192 VM_SV_sound,                                    // #8 void(entity e, float chan, string samp) sound (QUAKE)
3193 VM_normalize,                                   // #9 vector(vector v) normalize (QUAKE)
3194 VM_error,                                               // #10 void(string e) error (QUAKE)
3195 VM_objerror,                                    // #11 void(string e) objerror (QUAKE)
3196 VM_vlen,                                                // #12 float(vector v) vlen (QUAKE)
3197 VM_vectoyaw,                                    // #13 float(vector v) vectoyaw (QUAKE)
3198 VM_spawn,                                               // #14 entity() spawn (QUAKE)
3199 VM_remove,                                              // #15 void(entity e) remove (QUAKE)
3200 VM_SV_traceline,                                // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3201 VM_SV_checkclient,                              // #17 entity() checkclient (QUAKE)
3202 VM_find,                                                // #18 entity(entity start, .string fld, string match) find (QUAKE)
3203 VM_SV_precache_sound,                   // #19 void(string s) precache_sound (QUAKE)
3204 VM_SV_precache_model,                   // #20 void(string s) precache_model (QUAKE)
3205 VM_SV_stuffcmd,                                 // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3206 VM_SV_findradius,                               // #22 entity(vector org, float rad) findradius (QUAKE)
3207 VM_bprint,                                              // #23 void(string s, ...) bprint (QUAKE)
3208 VM_SV_sprint,                                   // #24 void(entity client, string s, ...) sprint (QUAKE)
3209 VM_dprint,                                              // #25 void(string s, ...) dprint (QUAKE)
3210 VM_ftos,                                                // #26 string(float f) ftos (QUAKE)
3211 VM_vtos,                                                // #27 string(vector v) vtos (QUAKE)
3212 VM_coredump,                                    // #28 void() coredump (QUAKE)
3213 VM_traceon,                                             // #29 void() traceon (QUAKE)
3214 VM_traceoff,                                    // #30 void() traceoff (QUAKE)
3215 VM_eprint,                                              // #31 void(entity e) eprint (QUAKE)
3216 VM_SV_walkmove,                                 // #32 float(float yaw, float dist) walkmove (QUAKE)
3217 NULL,                                                   // #33 (QUAKE)
3218 VM_SV_droptofloor,                              // #34 float() droptofloor (QUAKE)
3219 VM_SV_lightstyle,                               // #35 void(float style, string value) lightstyle (QUAKE)
3220 VM_rint,                                                // #36 float(float v) rint (QUAKE)
3221 VM_floor,                                               // #37 float(float v) floor (QUAKE)
3222 VM_ceil,                                                // #38 float(float v) ceil (QUAKE)
3223 NULL,                                                   // #39 (QUAKE)
3224 VM_SV_checkbottom,                              // #40 float(entity e) checkbottom (QUAKE)
3225 VM_SV_pointcontents,                    // #41 float(vector v) pointcontents (QUAKE)
3226 NULL,                                                   // #42 (QUAKE)
3227 VM_fabs,                                                // #43 float(float f) fabs (QUAKE)
3228 VM_SV_aim,                                              // #44 vector(entity e, float speed) aim (QUAKE)
3229 VM_cvar,                                                // #45 float(string s) cvar (QUAKE)
3230 VM_localcmd,                                    // #46 void(string s) localcmd (QUAKE)
3231 VM_nextent,                                             // #47 entity(entity e) nextent (QUAKE)
3232 VM_SV_particle,                                 // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3233 VM_changeyaw,                                   // #49 void() ChangeYaw (QUAKE)
3234 NULL,                                                   // #50 (QUAKE)
3235 VM_vectoangles,                                 // #51 vector(vector v) vectoangles (QUAKE)
3236 VM_SV_WriteByte,                                // #52 void(float to, float f) WriteByte (QUAKE)
3237 VM_SV_WriteChar,                                // #53 void(float to, float f) WriteChar (QUAKE)
3238 VM_SV_WriteShort,                               // #54 void(float to, float f) WriteShort (QUAKE)
3239 VM_SV_WriteLong,                                // #55 void(float to, float f) WriteLong (QUAKE)
3240 VM_SV_WriteCoord,                               // #56 void(float to, float f) WriteCoord (QUAKE)
3241 VM_SV_WriteAngle,                               // #57 void(float to, float f) WriteAngle (QUAKE)
3242 VM_SV_WriteString,                              // #58 void(float to, string s) WriteString (QUAKE)
3243 VM_SV_WriteEntity,                              // #59 void(float to, entity e) WriteEntity (QUAKE)
3244 VM_sin,                                                 // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3245 VM_cos,                                                 // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3246 VM_sqrt,                                                // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3247 VM_changepitch,                                 // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3248 VM_SV_tracetoss,                                // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3249 VM_etos,                                                // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3250 NULL,                                                   // #66 (QUAKE)
3251 VM_SV_MoveToGoal,                               // #67 void(float step) movetogoal (QUAKE)
3252 VM_precache_file,                               // #68 string(string s) precache_file (QUAKE)
3253 VM_SV_makestatic,                               // #69 void(entity e) makestatic (QUAKE)
3254 VM_changelevel,                                 // #70 void(string s) changelevel (QUAKE)
3255 NULL,                                                   // #71 (QUAKE)
3256 VM_cvar_set,                                    // #72 void(string var, string val) cvar_set (QUAKE)
3257 VM_SV_centerprint,                              // #73 void(entity client, strings) centerprint (QUAKE)
3258 VM_SV_ambientsound,                             // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3259 VM_SV_precache_model,                   // #75 string(string s) precache_model2 (QUAKE)
3260 VM_SV_precache_sound,                   // #76 string(string s) precache_sound2 (QUAKE)
3261 VM_precache_file,                               // #77 string(string s) precache_file2 (QUAKE)
3262 VM_SV_setspawnparms,                    // #78 void(entity e) setspawnparms (QUAKE)
3263 NULL,                                                   // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3264 NULL,                                                   // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3265 VM_stof,                                                // #81 float(string s) stof (FRIK_FILE)
3266 NULL,                                                   // #82 void(vector where, float set) multicast (QUAKEWORLD)
3267 NULL,                                                   // #83 (QUAKE)
3268 NULL,                                                   // #84 (QUAKE)
3269 NULL,                                                   // #85 (QUAKE)
3270 NULL,                                                   // #86 (QUAKE)
3271 NULL,                                                   // #87 (QUAKE)
3272 NULL,                                                   // #88 (QUAKE)
3273 NULL,                                                   // #89 (QUAKE)
3274 VM_SV_tracebox,                                 // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3275 VM_randomvec,                                   // #91 vector() randomvec (DP_QC_RANDOMVEC)
3276 VM_SV_getlight,                                 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3277 VM_registercvar,                                // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3278 VM_min,                                                 // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3279 VM_max,                                                 // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3280 VM_bound,                                               // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3281 VM_pow,                                                 // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3282 VM_findfloat,                                   // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3283 VM_checkextension,                              // #99 float(string s) checkextension (the basis of the extension system)
3284 // FrikaC and Telejano range  #100-#199
3285 NULL,                                                   // #100
3286 NULL,                                                   // #101
3287 NULL,                                                   // #102
3288 NULL,                                                   // #103
3289 NULL,                                                   // #104
3290 NULL,                                                   // #105
3291 NULL,                                                   // #106
3292 NULL,                                                   // #107
3293 NULL,                                                   // #108
3294 NULL,                                                   // #109
3295 VM_fopen,                                               // #110 float(string filename, float mode) fopen (FRIK_FILE)
3296 VM_fclose,                                              // #111 void(float fhandle) fclose (FRIK_FILE)
3297 VM_fgets,                                               // #112 string(float fhandle) fgets (FRIK_FILE)
3298 VM_fputs,                                               // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3299 VM_strlen,                                              // #114 float(string s) strlen (FRIK_FILE)
3300 VM_strcat,                                              // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3301 VM_substring,                                   // #116 string(string s, float start, float length) substring (FRIK_FILE)
3302 VM_stov,                                                // #117 vector(string) stov (FRIK_FILE)
3303 VM_strzone,                                             // #118 string(string s) strzone (FRIK_FILE)
3304 VM_strunzone,                                   // #119 void(string s) strunzone (FRIK_FILE)
3305 NULL,                                                   // #120
3306 NULL,                                                   // #121
3307 NULL,                                                   // #122
3308 NULL,                                                   // #123
3309 NULL,                                                   // #124
3310 NULL,                                                   // #125
3311 NULL,                                                   // #126
3312 NULL,                                                   // #127
3313 NULL,                                                   // #128
3314 NULL,                                                   // #129
3315 NULL,                                                   // #130
3316 NULL,                                                   // #131
3317 NULL,                                                   // #132
3318 NULL,                                                   // #133
3319 NULL,                                                   // #134
3320 NULL,                                                   // #135
3321 NULL,                                                   // #136
3322 NULL,                                                   // #137
3323 NULL,                                                   // #138
3324 NULL,                                                   // #139
3325 NULL,                                                   // #140
3326 NULL,                                                   // #141
3327 NULL,                                                   // #142
3328 NULL,                                                   // #143
3329 NULL,                                                   // #144
3330 NULL,                                                   // #145
3331 NULL,                                                   // #146
3332 NULL,                                                   // #147
3333 NULL,                                                   // #148
3334 NULL,                                                   // #149
3335 NULL,                                                   // #150
3336 NULL,                                                   // #151
3337 NULL,                                                   // #152
3338 NULL,                                                   // #153
3339 NULL,                                                   // #154
3340 NULL,                                                   // #155
3341 NULL,                                                   // #156
3342 NULL,                                                   // #157
3343 NULL,                                                   // #158
3344 NULL,                                                   // #159
3345 NULL,                                                   // #160
3346 NULL,                                                   // #161
3347 NULL,                                                   // #162
3348 NULL,                                                   // #163
3349 NULL,                                                   // #164
3350 NULL,                                                   // #165
3351 NULL,                                                   // #166
3352 NULL,                                                   // #167
3353 NULL,                                                   // #168
3354 NULL,                                                   // #169
3355 NULL,                                                   // #170
3356 NULL,                                                   // #171
3357 NULL,                                                   // #172
3358 NULL,                                                   // #173
3359 NULL,                                                   // #174
3360 NULL,                                                   // #175
3361 NULL,                                                   // #176
3362 NULL,                                                   // #177
3363 NULL,                                                   // #178
3364 NULL,                                                   // #179
3365 NULL,                                                   // #180
3366 NULL,                                                   // #181
3367 NULL,                                                   // #182
3368 NULL,                                                   // #183
3369 NULL,                                                   // #184
3370 NULL,                                                   // #185
3371 NULL,                                                   // #186
3372 NULL,                                                   // #187
3373 NULL,                                                   // #188
3374 NULL,                                                   // #189
3375 NULL,                                                   // #190
3376 NULL,                                                   // #191
3377 NULL,                                                   // #192
3378 NULL,                                                   // #193
3379 NULL,                                                   // #194
3380 NULL,                                                   // #195
3381 NULL,                                                   // #196
3382 NULL,                                                   // #197
3383 NULL,                                                   // #198
3384 NULL,                                                   // #199
3385 // FTEQW range #200-#299
3386 NULL,                                                   // #200
3387 NULL,                                                   // #201
3388 NULL,                                                   // #202
3389 NULL,                                                   // #203
3390 NULL,                                                   // #204
3391 NULL,                                                   // #205
3392 NULL,                                                   // #206
3393 NULL,                                                   // #207
3394 NULL,                                                   // #208
3395 NULL,                                                   // #209
3396 NULL,                                                   // #210
3397 NULL,                                                   // #211
3398 NULL,                                                   // #212
3399 NULL,                                                   // #213