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