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