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