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