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