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