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