6 //============================================================================
11 const char *vm_sv_extensions =
16 "DP_CON_ALIASPARAMETERS "
25 "DP_CSQC_ENTITYWORLDOBJECT "
26 "DP_CSQC_ENTITYMODELLIGHT "
27 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
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 "
36 "DP_CSQC_V_CALCREFDEF_WIP1 "
37 "DP_CSQC_V_CALCREFDEF_WIP2 "
41 "DP_EF_DYNAMICMODELLIGHT "
50 "DP_EF_RESTARTANIM_BIT "
55 "DP_ENT_CUSTOMCOLORMAP "
56 "DP_ENT_EXTERIORMODELTOCLIENT "
59 "DP_ENT_LOWPRECISION "
61 "DP_ENT_TRAILEFFECTNUM "
63 "DP_GFX_EXTERNALTEXTURES "
64 "DP_GFX_EXTERNALTEXTURES_PERMAP "
66 "DP_GFX_MODEL_INTERPOLATION "
67 "DP_GFX_QUAKE3MODELTAGS "
71 "DP_GFX_FONTS_FREETYPE "
73 "DP_FONT_VARIABLEWIDTH "
75 "DP_HALFLIFE_MAP_CVAR "
78 "DP_LIGHTSTYLE_STATICVALUE "
82 "DP_MOVETYPEBOUNCEMISSILE "
83 "DP_MOVETYPEFLYWORLDONLY "
86 "DP_QC_ASINACOSATANATAN2TAN "
92 "DP_QC_CVAR_DEFSTRING "
93 "DP_QC_CVAR_DESCRIPTION "
97 "DP_QC_DIGEST_SHA256 "
100 "DP_QC_ENTITYSTRING "
102 "DP_QC_EXTRESPONSEPACKET "
104 "DP_QC_FINDCHAINFLAGS "
105 "DP_QC_FINDCHAINFLOAT "
106 "DP_QC_FINDCHAIN_TOFIELD "
112 "DP_QC_GETSURFACETRIANGLE "
113 "DP_QC_GETSURFACEPOINTATTRIBUTE "
115 "DP_QC_GETTAGINFO_BONEPROPERTIES "
117 "DP_QC_GETTIME_CDTRACK "
121 "DP_QC_MULTIPLETEMPSTRINGS "
122 "DP_QC_NUM_FOR_EDICT "
124 "DP_QC_SINCOSSQRTPOW "
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 "
133 "DP_QC_TOKENIZEBYSEPARATOR "
134 "DP_QC_TOKENIZE_CONSOLE "
137 "DP_QC_TRACE_MOVETYPE_HITMODEL "
138 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
139 "DP_QC_UNLIMITEDTEMPSTRINGS "
143 "DP_QC_VECTOANGLES_WITH_ROLL "
144 "DP_QC_VECTORVECTORS "
151 "DP_SKELETONOBJECTS "
152 "DP_SND_DIRECTIONLESSATTNNONE "
154 "DP_SND_SOUND7_WIP1 "
155 "DP_SND_SOUND7_WIP2 "
159 "DP_SND_GETSOUNDTIME "
161 "DP_VIDEO_SUBTITLES "
165 "DP_SV_BOUNCEFACTOR "
166 "DP_SV_CLIENTCAMERA "
167 "DP_SV_CLIENTCOLORS "
170 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
171 "DP_SV_DISABLECLIENTPREDICTION "
172 "DP_SV_DISCARDABLEDEMO "
173 "DP_SV_DRAWONLYTOCLIENT "
176 "DP_SV_ENTITYCONTENTSTRANSITION "
177 "DP_SV_MODELFLAGS_AS_EFFECTS "
178 "DP_SV_MOVETYPESTEP_LANDEVENT "
180 "DP_SV_NODRAWTOCLIENT "
181 "DP_SV_ONENTITYNOSPAWNFUNCTION "
182 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
184 "DP_SV_PING_PACKETLOSS "
185 "DP_SV_PLAYERPHYSICS "
187 "DP_SV_POINTPARTICLES "
189 "DP_SV_PRECACHEANYTIME "
193 "DP_SV_ROTATINGBMODEL "
197 "DP_SV_SPAWNFUNC_PREFIX "
198 "DP_SV_WRITEPICTURE "
199 "DP_SV_WRITEUNTERMINATEDSTRING "
203 "DP_TE_EXPLOSIONRGB "
205 "DP_TE_PARTICLECUBE "
206 "DP_TE_PARTICLERAIN "
207 "DP_TE_PARTICLESNOW "
209 "DP_TE_QUADEFFECTS1 "
212 "DP_TE_STANDARDEFFECTBUILTINS "
213 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
218 "FTE_CSQC_SKELETONOBJECTS "
221 "KRIMZON_SV_PARSECLIENTCOMMAND "
224 "NEXUIZ_PLAYERMODEL "
226 "PRYDON_CLIENTCURSOR "
227 "TENEBRAE_GFX_DLIGHTS "
232 //"EXT_CSQC " // not ready yet
239 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.
241 setorigin (entity, origin)
244 static void VM_SV_setorigin(prvm_prog_t *prog)
248 VM_SAFEPARMCOUNT(2, VM_setorigin);
250 e = PRVM_G_EDICT(OFS_PARM0);
251 if (e == prog->edicts)
253 VM_Warning(prog, "setorigin: can not modify world entity\n");
256 if (e->priv.server->free)
258 VM_Warning(prog, "setorigin: can not modify free entity\n");
261 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), PRVM_serveredictvector(e, origin));
262 if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
263 e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
267 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
268 static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max, qboolean rotate)
272 for (i=0 ; i<3 ; i++)
274 prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
276 // set derived values
277 VectorCopy (min, PRVM_serveredictvector(e, mins));
278 VectorCopy (max, PRVM_serveredictvector(e, maxs));
279 VectorSubtract (max, min, PRVM_serveredictvector(e, size));
288 the size box is rotated by the current angle
289 LadyHavoc: no it isn't...
291 setsize (entity, minvector, maxvector)
294 static void VM_SV_setsize(prvm_prog_t *prog)
299 VM_SAFEPARMCOUNT(3, VM_setsize);
301 e = PRVM_G_EDICT(OFS_PARM0);
302 if (e == prog->edicts)
304 VM_Warning(prog, "setsize: can not modify world entity\n");
307 if (e->priv.server->free)
309 VM_Warning(prog, "setsize: can not modify free entity\n");
312 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
313 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
314 SetMinMaxSize(prog, e, mins, maxs, false);
322 setmodel(entity, model)
325 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
326 static void VM_SV_setmodel(prvm_prog_t *prog)
332 VM_SAFEPARMCOUNT(2, VM_setmodel);
334 e = PRVM_G_EDICT(OFS_PARM0);
335 if (e == prog->edicts)
337 VM_Warning(prog, "setmodel: can not modify world entity\n");
340 if (e->priv.server->free)
342 VM_Warning(prog, "setmodel: can not modify free entity\n");
345 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
346 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
347 PRVM_serveredictfloat(e, modelindex) = i;
349 mod = SV_GetModelByIndex(i);
353 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
354 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
356 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
359 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
366 single print to a specific client
368 sprint(clientent, value)
371 static void VM_SV_sprint(prvm_prog_t *prog)
375 char string[VM_STRINGTEMP_LENGTH];
377 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
379 VM_VarString(prog, 1, string, sizeof(string));
381 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
382 // LadyHavoc: div0 requested that sprintto world operate like print
389 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
391 VM_Warning(prog, "tried to centerprint to a non-client\n");
395 client = svs.clients + entnum-1;
396 if (!client->netconnection)
399 MSG_WriteChar(&client->netconnection->message,svc_print);
400 MSG_WriteString(&client->netconnection->message, string);
408 single print to a specific client
410 centerprint(clientent, value)
413 static void VM_SV_centerprint(prvm_prog_t *prog)
417 char string[VM_STRINGTEMP_LENGTH];
419 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
421 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
423 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
425 VM_Warning(prog, "tried to centerprint to a non-client\n");
429 client = svs.clients + entnum-1;
430 if (!client->netconnection)
433 VM_VarString(prog, 1, string, sizeof(string));
434 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
435 MSG_WriteString(&client->netconnection->message, string);
442 particle(origin, color, count)
445 static void VM_SV_particle(prvm_prog_t *prog)
451 VM_SAFEPARMCOUNT(4, VM_SV_particle);
453 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
454 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
455 color = (int)PRVM_G_FLOAT(OFS_PARM2);
456 count = (int)PRVM_G_FLOAT(OFS_PARM3);
457 SV_StartParticle (org, dir, color, count);
467 static void VM_SV_ambientsound(prvm_prog_t *prog)
471 prvm_vec_t vol, attenuation;
474 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
476 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
477 samp = PRVM_G_STRING(OFS_PARM1);
478 vol = PRVM_G_FLOAT(OFS_PARM2);
479 attenuation = PRVM_G_FLOAT(OFS_PARM3);
481 // check to see if samp was properly precached
482 soundnum = SV_SoundIndex(samp, 1);
490 // add an svc_spawnambient command to the level signon packet
493 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
495 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
497 MSG_WriteVector(&sv.signon, pos, sv.protocol);
499 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
500 MSG_WriteShort (&sv.signon, soundnum);
502 MSG_WriteByte (&sv.signon, soundnum);
504 MSG_WriteByte (&sv.signon, (int)(vol*255));
505 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
513 Each entity can have eight independant sound sources, like voice,
516 Channel 0 is an auto-allocate channel, the others override anything
517 already running on that entity/channel pair.
519 An attenuation of 0 will play full volume everywhere in the level.
520 Larger attenuations will drop off.
524 static void VM_SV_sound(prvm_prog_t *prog)
528 prvm_edict_t *entity;
534 VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
536 entity = PRVM_G_EDICT(OFS_PARM0);
537 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
538 sample = PRVM_G_STRING(OFS_PARM2);
539 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
542 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
546 attenuation = PRVM_G_FLOAT(OFS_PARM4);
550 pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
555 if(channel >= 8 && channel <= 15) // weird QW feature
557 flags |= CHANNELFLAG_RELIABLE;
563 // LadyHavoc: we only let the qc set certain flags, others are off-limits
564 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
567 if (nvolume < 0 || nvolume > 255)
569 VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
573 if (attenuation < 0 || attenuation > 4)
575 VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
579 channel = CHAN_USER2ENGINE(channel);
581 if (!IS_CHAN(channel))
583 VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
587 SV_StartSound (entity, channel, sample, nvolume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange);
594 Follows the same logic as VM_SV_sound, except instead of
595 an entity, an origin for the sound is provided, and channel
596 is omitted (since no entity is being tracked).
600 static void VM_SV_pointsound(prvm_prog_t *prog)
608 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
610 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
611 sample = PRVM_G_STRING(OFS_PARM1);
612 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
613 attenuation = PRVM_G_FLOAT(OFS_PARM3);
614 pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
616 if (nvolume < 0 || nvolume > 255)
618 VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
622 if (attenuation < 0 || attenuation > 4)
624 VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
628 SV_StartPointSound (org, sample, nvolume, attenuation, pitchchange);
635 Used for use tracing and shot targeting
636 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
637 if the tryents flag is set.
639 traceline (vector1, vector2, movetype, ignore)
642 static void VM_SV_traceline(prvm_prog_t *prog)
649 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
651 prog->xfunction->builtinsprofile += 30;
653 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
654 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
655 move = (int)PRVM_G_FLOAT(OFS_PARM2);
656 ent = PRVM_G_EDICT(OFS_PARM3);
658 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]))
659 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));
661 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value);
663 VM_SetTraceGlobals(prog, &trace);
671 Used for use tracing and shot targeting
672 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
673 if the tryents flag is set.
675 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
678 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
679 static void VM_SV_tracebox(prvm_prog_t *prog)
681 vec3_t v1, v2, m1, m2;
686 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
688 prog->xfunction->builtinsprofile += 30;
690 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
691 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
692 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
693 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
694 move = (int)PRVM_G_FLOAT(OFS_PARM4);
695 ent = PRVM_G_EDICT(OFS_PARM5);
697 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]))
698 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));
700 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value);
702 VM_SetTraceGlobals(prog, &trace);
705 static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
709 vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
710 vec3_t original_origin;
711 vec3_t original_velocity;
712 vec3_t original_angles;
713 vec3_t original_avelocity;
716 VectorCopy(PRVM_serveredictvector(tossent, origin) , original_origin );
717 VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
718 VectorCopy(PRVM_serveredictvector(tossent, angles) , original_angles );
719 VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
721 gravity = PRVM_serveredictfloat(tossent, gravity);
724 gravity *= sv_gravity.value * 0.025;
726 for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
728 SV_CheckVelocity (tossent);
729 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
730 VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
731 VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
732 VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
733 VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
734 VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
735 VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
736 trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value);
737 VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
738 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
740 if (trace.fraction < 1)
744 VectorCopy(original_origin , PRVM_serveredictvector(tossent, origin) );
745 VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
746 VectorCopy(original_angles , PRVM_serveredictvector(tossent, angles) );
747 VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
752 static void VM_SV_tracetoss(prvm_prog_t *prog)
756 prvm_edict_t *ignore;
758 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
760 prog->xfunction->builtinsprofile += 600;
762 ent = PRVM_G_EDICT(OFS_PARM0);
763 if (ent == prog->edicts)
765 VM_Warning(prog, "tracetoss: can not use world entity\n");
768 ignore = PRVM_G_EDICT(OFS_PARM1);
770 trace = SV_Trace_Toss(prog, ent, ignore);
772 VM_SetTraceGlobals(prog, &trace);
775 //============================================================================
777 static int checkpvsbytes;
778 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
780 static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
786 // cycle to the next one
788 check = bound(1, check, svs.maxclients);
789 if (check == svs.maxclients)
797 prog->xfunction->builtinsprofile++;
799 if (i == svs.maxclients+1)
801 // look up the client's edict
802 ent = PRVM_EDICT_NUM(i);
803 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
804 if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
806 // found a valid client (possibly the same one again)
810 // get the PVS for the entity
811 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
813 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
814 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
823 Returns a client (or object that has a client enemy) that would be a
826 If there is more than one valid option, they are cycled each frame
828 If (self.origin + self.viewofs) is not in the PVS of the current target,
829 it is not returned at all.
834 int c_invis, c_notvis;
835 static void VM_SV_checkclient(prvm_prog_t *prog)
837 prvm_edict_t *ent, *self;
840 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
842 // find a new check if on a new frame
843 if (sv.time - sv.lastchecktime >= 0.1)
845 sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
846 sv.lastchecktime = sv.time;
849 // return check if it might be visible
850 ent = PRVM_EDICT_NUM(sv.lastcheck);
851 if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
853 VM_RETURN_EDICT(prog->edicts);
857 // if current entity can't possibly see the check entity, return 0
858 self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
859 VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
860 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
863 VM_RETURN_EDICT(prog->edicts);
867 // might be able to see it
869 VM_RETURN_EDICT(ent);
872 //============================================================================
878 Checks if an entity is in a point's PVS.
879 Should be fast but can be inexact.
881 float checkpvs(vector viewpos, entity viewee) = #240;
884 static void VM_SV_checkpvs(prvm_prog_t *prog)
886 vec3_t viewpos, absmin, absmax;
887 prvm_edict_t *viewee;
892 unsigned char fatpvs[MAX_MAP_LEAFS/8];
895 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
896 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
897 viewee = PRVM_G_EDICT(OFS_PARM1);
899 if(viewee->priv.server->free)
901 VM_Warning(prog, "checkpvs: can not check free entity\n");
902 PRVM_G_FLOAT(OFS_RETURN) = 4;
907 if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
909 // no PVS support on this worldmodel... darn
910 PRVM_G_FLOAT(OFS_RETURN) = 3;
913 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
916 // viewpos isn't in any PVS... darn
917 PRVM_G_FLOAT(OFS_RETURN) = 2;
920 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
921 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
922 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
924 // using fat PVS like FTEQW does (slow)
925 if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
927 // no PVS support on this worldmodel... darn
928 PRVM_G_FLOAT(OFS_RETURN) = 3;
931 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
934 // viewpos isn't in any PVS... darn
935 PRVM_G_FLOAT(OFS_RETURN) = 2;
938 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
939 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
940 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
949 Sends text over to the client's execution buffer
951 stuffcmd (clientent, value, ...)
954 static void VM_SV_stuffcmd(prvm_prog_t *prog)
958 char string[VM_STRINGTEMP_LENGTH];
960 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
962 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
963 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
965 VM_Warning(prog, "Can't stuffcmd to a non-client\n");
969 VM_VarString(prog, 1, string, sizeof(string));
972 host_client = svs.clients + entnum-1;
973 Host_ClientCommands ("%s", string);
981 Returns a chain of entities that have origins within a spherical area
983 findradius (origin, radius)
986 static void VM_SV_findradius(prvm_prog_t *prog)
988 prvm_edict_t *ent, *chain;
989 vec_t radius, radius2;
990 vec3_t org, eorg, mins, maxs;
993 static prvm_edict_t *touchedicts[MAX_EDICTS];
996 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
999 chainfield = PRVM_G_INT(OFS_PARM2);
1001 chainfield = prog->fieldoffsets.chain;
1003 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
1005 chain = (prvm_edict_t *)prog->edicts;
1007 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1008 radius = PRVM_G_FLOAT(OFS_PARM1);
1009 radius2 = radius * radius;
1011 mins[0] = org[0] - (radius + 1);
1012 mins[1] = org[1] - (radius + 1);
1013 mins[2] = org[2] - (radius + 1);
1014 maxs[0] = org[0] + (radius + 1);
1015 maxs[1] = org[1] + (radius + 1);
1016 maxs[2] = org[2] + (radius + 1);
1017 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1018 if (numtouchedicts > MAX_EDICTS)
1020 // this never happens
1021 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1022 numtouchedicts = MAX_EDICTS;
1024 for (i = 0;i < numtouchedicts;i++)
1026 ent = touchedicts[i];
1027 prog->xfunction->builtinsprofile++;
1028 // Quake did not return non-solid entities but darkplaces does
1029 // (note: this is the reason you can't blow up fallen zombies)
1030 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1032 // LadyHavoc: compare against bounding box rather than center so it
1033 // doesn't miss large objects, and use DotProduct instead of Length
1034 // for a major speedup
1035 VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
1036 if (sv_gameplayfix_findradiusdistancetobox.integer)
1038 eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
1039 eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
1040 eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
1043 VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
1044 if (DotProduct(eorg, eorg) < radius2)
1046 PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
1051 VM_RETURN_EDICT(chain);
1054 static void VM_SV_precache_sound(prvm_prog_t *prog)
1056 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1057 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1060 static void VM_SV_precache_model(prvm_prog_t *prog)
1062 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1063 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1064 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1071 float(float yaw, float dist[, settrace]) walkmove
1074 static void VM_SV_walkmove(prvm_prog_t *prog)
1083 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1085 // assume failure if it returns early
1086 PRVM_G_FLOAT(OFS_RETURN) = 0;
1088 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1089 if (ent == prog->edicts)
1091 VM_Warning(prog, "walkmove: can not modify world entity\n");
1094 if (ent->priv.server->free)
1096 VM_Warning(prog, "walkmove: can not modify free entity\n");
1099 yaw = PRVM_G_FLOAT(OFS_PARM0);
1100 dist = PRVM_G_FLOAT(OFS_PARM1);
1101 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1103 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1106 yaw = yaw*M_PI*2 / 360;
1108 move[0] = cos(yaw)*dist;
1109 move[1] = sin(yaw)*dist;
1112 // save program state, because SV_movestep may call other progs
1113 oldf = prog->xfunction;
1114 oldself = PRVM_serverglobaledict(self);
1116 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1119 // restore program state
1120 prog->xfunction = oldf;
1121 PRVM_serverglobaledict(self) = oldself;
1128 float(float yaw, float dist[, settrace]) walkmovedist (EXT_WRATH)
1131 static void VM_SV_walkmovedist(prvm_prog_t *prog)
1135 vec3_t move, oldorg, neworg;
1140 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmovedist);
1142 // assume failure if it returns early
1143 PRVM_G_FLOAT(OFS_RETURN) = 0;
1145 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1146 if (ent == prog->edicts)
1148 VM_Warning(prog, "walkmove: can not modify world entity\n");
1151 if (ent->priv.server->free)
1153 VM_Warning(prog, "walkmove: can not modify free entity\n");
1156 yaw = PRVM_G_FLOAT(OFS_PARM0);
1157 dist = PRVM_G_FLOAT(OFS_PARM1);
1158 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1160 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1163 yaw = yaw*M_PI*2 / 360;
1165 move[0] = cos(yaw)*dist;
1166 move[1] = sin(yaw)*dist;
1169 // save origin before move
1170 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
1172 // save program state, because SV_movestep may call other progs
1173 oldf = prog->xfunction;
1174 oldself = PRVM_serverglobaledict(self);
1176 SV_movestep(ent, move, true, false, settrace);
1178 // restore program state
1179 prog->xfunction = oldf;
1180 PRVM_serverglobaledict(self) = oldself;
1182 // save origin after move
1183 VectorCopy (PRVM_serveredictvector(ent, origin), neworg);
1185 // return distance traveled
1186 PRVM_G_FLOAT(OFS_RETURN) = VectorDistance(oldorg, neworg);
1197 static void VM_SV_droptofloor(prvm_prog_t *prog)
1200 vec3_t end, entorigin, entmins, entmaxs;
1203 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1205 // assume failure if it returns early
1206 PRVM_G_FLOAT(OFS_RETURN) = 0;
1208 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1209 if (ent == prog->edicts)
1211 VM_Warning(prog, "droptofloor: can not modify world entity\n");
1214 if (ent->priv.server->free)
1216 VM_Warning(prog, "droptofloor: can not modify free entity\n");
1220 VectorCopy (PRVM_serveredictvector(ent, origin), end);
1223 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1224 SV_NudgeOutOfSolid(ent);
1226 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
1227 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
1228 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
1229 trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1230 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1233 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]);
1234 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
1235 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1236 VectorSubtract(trace.endpos, offset, trace.endpos);
1237 if (trace.startsolid)
1239 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]);
1241 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1242 PRVM_serveredictedict(ent, groundentity) = 0;
1243 PRVM_G_FLOAT(OFS_RETURN) = 1;
1245 else if (trace.fraction < 1)
1247 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]);
1248 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1249 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1250 SV_NudgeOutOfSolid(ent);
1252 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1253 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1254 PRVM_G_FLOAT(OFS_RETURN) = 1;
1255 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1256 ent->priv.server->suspendedinairflag = true;
1261 if (!trace.allsolid && trace.fraction < 1)
1263 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1265 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1266 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1267 PRVM_G_FLOAT(OFS_RETURN) = 1;
1268 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1269 ent->priv.server->suspendedinairflag = true;
1278 void(float style, string value) lightstyle
1281 static void VM_SV_lightstyle(prvm_prog_t *prog)
1288 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1290 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1291 val = PRVM_G_STRING(OFS_PARM1);
1293 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1294 prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
1297 // change the string in sv
1298 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1300 // send message to all clients on this server
1301 if (sv.state != ss_active)
1304 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1306 if (client->active && client->netconnection)
1308 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1309 MSG_WriteChar (&client->netconnection->message,style);
1310 MSG_WriteString (&client->netconnection->message, val);
1320 static void VM_SV_checkbottom(prvm_prog_t *prog)
1322 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1323 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1331 static void VM_SV_pointcontents(prvm_prog_t *prog)
1334 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1335 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
1336 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(point));
1343 Pick a vector for the player to shoot along
1344 vector aim(entity, missilespeed)
1347 static void VM_SV_aim(prvm_prog_t *prog)
1349 prvm_edict_t *ent, *check, *bestent;
1350 vec3_t start, dir, end, bestdir;
1353 float dist, bestdist;
1356 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1358 // assume failure if it returns early
1359 VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1360 // if sv_aim is so high it can't possibly accept anything, skip out early
1361 if (sv_aim.value >= 1)
1364 ent = PRVM_G_EDICT(OFS_PARM0);
1365 if (ent == prog->edicts)
1367 VM_Warning(prog, "aim: can not use world entity\n");
1370 if (ent->priv.server->free)
1372 VM_Warning(prog, "aim: can not use free entity\n");
1375 //speed = PRVM_G_FLOAT(OFS_PARM1);
1377 VectorCopy (PRVM_serveredictvector(ent, origin), start);
1380 // try sending a trace straight
1381 VectorCopy (PRVM_serverglobalvector(v_forward), dir);
1382 VectorMA (start, 2048, dir, end);
1383 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1384 if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
1385 && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
1387 VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1392 // try all possible entities
1393 VectorCopy (dir, bestdir);
1394 bestdist = sv_aim.value;
1397 check = PRVM_NEXT_EDICT(prog->edicts);
1398 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1400 prog->xfunction->builtinsprofile++;
1401 if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
1405 if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
1406 continue; // don't aim at teammate
1407 for (j=0 ; j<3 ; j++)
1408 end[j] = PRVM_serveredictvector(check, origin)[j]
1409 + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
1410 VectorSubtract (end, start, dir);
1411 VectorNormalize (dir);
1412 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1413 if (dist < bestdist)
1414 continue; // to far to turn
1415 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1416 if (tr.ent == check)
1417 { // can shoot at this one
1425 VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
1426 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1427 VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
1429 VectorNormalize (end);
1430 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1434 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1439 ===============================================================================
1443 ===============================================================================
1446 #define MSG_BROADCAST 0 // unreliable to all
1447 #define MSG_ONE 1 // reliable to one (msg_entity)
1448 #define MSG_ALL 2 // reliable to all
1449 #define MSG_INIT 3 // write to the init string
1450 #define MSG_ENTITY 5
1452 static sizebuf_t *WriteDest(prvm_prog_t *prog)
1458 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1462 return &sv.datagram;
1465 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
1466 entnum = PRVM_NUM_FOR_EDICT(ent);
1467 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1469 VM_Warning(prog, "WriteDest: tried to write to non-client\n");
1470 return &sv.reliable_datagram;
1473 return &svs.clients[entnum-1].netconnection->message;
1476 VM_Warning(prog, "WriteDest: bad destination\n");
1478 return &sv.reliable_datagram;
1484 return sv.writeentitiestoclient_msg;
1490 static void VM_SV_WriteByte(prvm_prog_t *prog)
1492 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1493 MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1496 static void VM_SV_WriteChar(prvm_prog_t *prog)
1498 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1499 MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1502 static void VM_SV_WriteShort(prvm_prog_t *prog)
1504 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1505 MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1508 static void VM_SV_WriteLong(prvm_prog_t *prog)
1510 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1511 MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1514 static void VM_SV_WriteAngle(prvm_prog_t *prog)
1516 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1517 MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1520 static void VM_SV_WriteCoord(prvm_prog_t *prog)
1522 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1523 MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1526 static void VM_SV_WriteString(prvm_prog_t *prog)
1528 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1529 MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1532 static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
1534 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1535 MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1539 static void VM_SV_WriteEntity(prvm_prog_t *prog)
1541 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1542 MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
1545 // writes a picture as at most size bytes of data
1547 // IMGNAME \0 SIZE(short) IMGDATA
1548 // if failed to read/compress:
1550 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1551 static void VM_SV_WritePicture(prvm_prog_t *prog)
1553 const char *imgname;
1557 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1559 imgname = PRVM_G_STRING(OFS_PARM1);
1560 size = (size_t) PRVM_G_FLOAT(OFS_PARM2);
1564 MSG_WriteString(WriteDest(prog), imgname);
1565 if(Image_Compress(imgname, size, &buf, &size))
1568 MSG_WriteShort(WriteDest(prog), (int)size);
1569 SZ_Write(WriteDest(prog), (unsigned char *) buf, (int)size);
1574 MSG_WriteShort(WriteDest(prog), 0);
1578 //////////////////////////////////////////////////////////
1580 static void VM_SV_makestatic(prvm_prog_t *prog)
1585 // allow 0 parameters due to an id1 qc bug in which this function is used
1586 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1587 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1589 if (prog->argc >= 1)
1590 ent = PRVM_G_EDICT(OFS_PARM0);
1592 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1593 if (ent == prog->edicts)
1595 VM_Warning(prog, "makestatic: can not modify world entity\n");
1598 if (ent->priv.server->free)
1600 VM_Warning(prog, "makestatic: can not modify free entity\n");
1605 if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
1610 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1611 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1612 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1614 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1616 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1617 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1618 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1622 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1623 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1624 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1627 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
1628 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
1629 for (i=0 ; i<3 ; i++)
1631 MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
1632 MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
1635 // throw the entity away now
1636 PRVM_ED_Free(prog, ent);
1639 //=============================================================================
1646 static void VM_SV_setspawnparms(prvm_prog_t *prog)
1652 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1654 ent = PRVM_G_EDICT(OFS_PARM0);
1655 i = PRVM_NUM_FOR_EDICT(ent);
1656 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1658 Con_Print("tried to setspawnparms on a non-client\n");
1662 // copy spawn parms out of the client_t
1663 client = svs.clients + i-1;
1664 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1665 (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
1672 Returns a color vector indicating the lighting at the requested point.
1674 (Internal Operation note: actually measures the light beneath the point, just like
1675 the model lighting on the client)
1680 static void VM_SV_getlight(prvm_prog_t *prog)
1682 vec3_t ambientcolor, diffusecolor, diffusenormal;
1684 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1685 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
1686 VectorClear(ambientcolor);
1687 VectorClear(diffusecolor);
1688 VectorClear(diffusenormal);
1689 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1690 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1691 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1696 unsigned char type; // 1/2/8 or 0 to indicate unused
1700 static customstat_t vm_customstats[MAX_CL_STATS]; // matches the regular stat numbers, but only MIN_VM_STAT to MAX_VM_STAT range is used if things are working properly (can register stats from MAX_VM_STAT to MAX_CL_STATS but will warn)
1701 static int vm_customstats_last;
1703 void VM_CustomStats_Clear (void)
1705 memset(vm_customstats, 0, sizeof(vm_customstats));
1706 vm_customstats_last = -1;
1709 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1711 prvm_prog_t *prog = SVVM_prog;
1719 for(i=MIN_VM_STAT; i<=vm_customstats_last ;i++)
1721 if(!vm_customstats[i].type)
1723 switch(vm_customstats[i].type)
1725 //string as 16 bytes
1728 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1729 stats[i] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1730 stats[i+1] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1731 stats[i+2] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1732 stats[i+3] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1734 //float field sent as-is
1736 // can't directly use PRVM_E_INT on the field because it may be PRVM_64 and a double is not the representation we want to send
1737 u.f = PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1740 //integer value of float field
1742 stats[i] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1750 // void(float index, float type, .void field) SV_AddStat = #232;
1751 // Set up an auto-sent player stat.
1752 // Client's get thier own fields sent to them. Index may not be less than 32.
1753 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1754 // 1: string (4 stats carrying a total of 16 charactures)
1755 // 2: float (one stat, float converted to an integer for transportation)
1756 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1757 static void VM_SV_AddStat(prvm_prog_t *prog)
1761 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1763 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1764 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1765 off = PRVM_G_INT (OFS_PARM2);
1774 VM_Warning(prog, "PF_SV_AddStat: unrecognized type %i - supported types are 1 (string up to 16 bytes, takes 4 stat slots), 2 (truncate to int32), 8 (send as float)", type);
1780 VM_Warning(prog, "PF_SV_AddStat: index (%i) may not be less than %i\n", i, MIN_VM_STAT);
1784 if (i >= MAX_CL_STATS)
1786 VM_Warning(prog, "PF_SV_AddStat: index (%i) >= MAX_CL_STATS (%i), not supported by protocol, and AddStat beyond MAX_VM_STAT (%i) conflicts with engine MOVEVARS\n", i, MAX_CL_STATS, MAX_VM_STAT);
1790 if (i > (MAX_CL_STATS - 4) && type == 1)
1792 VM_Warning(prog, "PF_SV_AddStat: index (%i) > (MAX_CL_STATS (%i) - 4) with string type won't fit in the protocol, and AddStat beyond MAX_VM_STAT conflicts with engine MOVEVARS\n", i, MAX_CL_STATS);
1796 // these are hazardous to override but sort of allowed if one wants to be adventurous... and enjoys warnings.
1797 if (i < MIN_VM_STAT)
1798 VM_Warning(prog, "PF_SV_AddStat: index (%i) < MIN_VM_STAT (%i) may conflict with engine stats - allowed, but this may break things\n", i, MIN_VM_STAT);
1799 else if (i >= MAX_VM_STAT)
1800 VM_Warning(prog, "PF_SV_AddStat: index (%i) >= MAX_VM_STAT (%i) conflicts with engine stats - allowed, but this may break slowmo and stuff\n", i, MAX_VM_STAT);
1801 else if (i > (MAX_VM_STAT - 4) && type == 1)
1802 VM_Warning(prog, "PF_SV_AddStat: index (%i) >= MAX_VM_STAT (%i) - 4 with string type won't fit within MAX_VM_STAT, thus conflicting with engine stats - allowed, but this may break slowmo and stuff\n", i, MAX_VM_STAT);
1804 vm_customstats[i].type = type;
1805 vm_customstats[i].fieldoffset = off;
1806 if(vm_customstats_last < i)
1807 vm_customstats_last = i;
1814 copies data from one entity to another
1816 copyentity(src, dst)
1819 static void VM_SV_copyentity(prvm_prog_t *prog)
1821 prvm_edict_t *in, *out;
1822 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1823 in = PRVM_G_EDICT(OFS_PARM0);
1824 if (in == prog->edicts)
1826 VM_Warning(prog, "copyentity: can not read world entity\n");
1829 if (in->priv.server->free)
1831 VM_Warning(prog, "copyentity: can not read free entity\n");
1834 out = PRVM_G_EDICT(OFS_PARM1);
1835 if (out == prog->edicts)
1837 VM_Warning(prog, "copyentity: can not modify world entity\n");
1840 if (out->priv.server->free)
1842 VM_Warning(prog, "copyentity: can not modify free entity\n");
1845 memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
1846 if (VectorCompare(PRVM_serveredictvector(out, absmin), PRVM_serveredictvector(out, absmax)))
1856 sets the color of a client and broadcasts the update to all connected clients
1858 setcolor(clientent, value)
1861 static void VM_SV_setcolor(prvm_prog_t *prog)
1866 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1867 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1868 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1870 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1872 Con_Print("tried to setcolor a non-client\n");
1876 client = svs.clients + entnum-1;
1879 PRVM_serveredictfloat(client->edict, clientcolors) = i;
1880 PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
1883 if (client->old_colors != client->colors)
1885 client->old_colors = client->colors;
1886 // send notification to all clients
1887 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1888 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1889 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1897 effect(origin, modelname, startframe, framecount, framerate)
1900 static void VM_SV_effect(prvm_prog_t *prog)
1905 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1906 s = PRVM_G_STRING(OFS_PARM1);
1909 VM_Warning(prog, "effect: no model specified\n");
1913 i = SV_ModelIndex(s, 1);
1916 VM_Warning(prog, "effect: model not precached\n");
1920 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1922 VM_Warning(prog, "effect: framecount < 1\n");
1926 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1928 VM_Warning(prog, "effect: framerate < 1\n");
1932 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1933 SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1936 static void VM_SV_te_blood(prvm_prog_t *prog)
1938 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1939 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1941 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1942 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1944 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1945 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1946 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1948 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1949 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1950 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1952 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1953 SV_FlushBroadcastMessages();
1956 static void VM_SV_te_bloodshower(prvm_prog_t *prog)
1958 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1959 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1961 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1962 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1964 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1965 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1966 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1968 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1969 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1970 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1972 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1974 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1975 SV_FlushBroadcastMessages();
1978 static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
1980 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1981 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1982 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1984 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1985 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1986 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1988 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1989 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1990 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1991 SV_FlushBroadcastMessages();
1994 static void VM_SV_te_particlecube(prvm_prog_t *prog)
1996 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1997 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1999 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2000 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2002 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2003 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2004 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2006 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2007 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2008 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2010 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2011 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2012 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2014 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2016 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2017 // gravity true/false
2018 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
2020 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
2021 SV_FlushBroadcastMessages();
2024 static void VM_SV_te_particlerain(prvm_prog_t *prog)
2026 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
2027 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2029 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2030 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2032 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2033 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2034 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2036 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2037 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2038 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2040 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2041 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2042 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2044 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2046 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2047 SV_FlushBroadcastMessages();
2050 static void VM_SV_te_particlesnow(prvm_prog_t *prog)
2052 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
2053 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2055 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2056 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2058 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2059 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2060 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2062 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2063 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2064 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2066 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2067 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2068 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2070 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2072 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2073 SV_FlushBroadcastMessages();
2076 static void VM_SV_te_spark(prvm_prog_t *prog)
2078 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
2079 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2081 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2082 MSG_WriteByte(&sv.datagram, TE_SPARK);
2084 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2085 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2086 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2088 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2089 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2090 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2092 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2093 SV_FlushBroadcastMessages();
2096 static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
2098 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
2099 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2100 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2102 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2103 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2104 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2105 SV_FlushBroadcastMessages();
2108 static void VM_SV_te_spikequad(prvm_prog_t *prog)
2110 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2111 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2112 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2114 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2115 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2116 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2117 SV_FlushBroadcastMessages();
2120 static void VM_SV_te_superspikequad(prvm_prog_t *prog)
2122 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2123 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2124 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2126 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2127 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2128 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2129 SV_FlushBroadcastMessages();
2132 static void VM_SV_te_explosionquad(prvm_prog_t *prog)
2134 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2135 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2136 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2138 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2139 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2140 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2141 SV_FlushBroadcastMessages();
2144 static void VM_SV_te_smallflash(prvm_prog_t *prog)
2146 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2147 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2148 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2150 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2151 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2152 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2153 SV_FlushBroadcastMessages();
2156 static void VM_SV_te_customflash(prvm_prog_t *prog)
2158 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2159 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2161 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2162 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2164 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2165 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2166 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2168 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2170 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2172 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2173 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2174 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2175 SV_FlushBroadcastMessages();
2178 static void VM_SV_te_gunshot(prvm_prog_t *prog)
2180 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2181 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2182 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2185 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2186 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2187 SV_FlushBroadcastMessages();
2190 static void VM_SV_te_spike(prvm_prog_t *prog)
2192 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2193 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2194 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2196 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2197 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2198 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2199 SV_FlushBroadcastMessages();
2202 static void VM_SV_te_superspike(prvm_prog_t *prog)
2204 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2205 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2206 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2208 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2209 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2210 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2211 SV_FlushBroadcastMessages();
2214 static void VM_SV_te_explosion(prvm_prog_t *prog)
2216 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2217 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2218 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2221 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2222 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2223 SV_FlushBroadcastMessages();
2226 static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
2228 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2229 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2230 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2232 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2233 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2234 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2235 SV_FlushBroadcastMessages();
2238 static void VM_SV_te_wizspike(prvm_prog_t *prog)
2240 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2241 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2242 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2244 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2245 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2246 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2247 SV_FlushBroadcastMessages();
2250 static void VM_SV_te_knightspike(prvm_prog_t *prog)
2252 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2253 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2254 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2256 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2257 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2258 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2259 SV_FlushBroadcastMessages();
2262 static void VM_SV_te_lavasplash(prvm_prog_t *prog)
2264 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2265 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2266 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2268 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2271 SV_FlushBroadcastMessages();
2274 static void VM_SV_te_teleport(prvm_prog_t *prog)
2276 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2277 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2280 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2281 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2282 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2283 SV_FlushBroadcastMessages();
2286 static void VM_SV_te_explosion2(prvm_prog_t *prog)
2288 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2289 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2290 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2292 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2293 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2294 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2296 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2297 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2298 SV_FlushBroadcastMessages();
2301 static void VM_SV_te_lightning1(prvm_prog_t *prog)
2303 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2304 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2305 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2307 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2309 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2310 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2311 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2313 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2314 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2315 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2316 SV_FlushBroadcastMessages();
2319 static void VM_SV_te_lightning2(prvm_prog_t *prog)
2321 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2322 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2323 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2325 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2327 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2334 SV_FlushBroadcastMessages();
2337 static void VM_SV_te_lightning3(prvm_prog_t *prog)
2339 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2340 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2341 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2343 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2345 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2346 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2347 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2349 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2350 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2351 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2352 SV_FlushBroadcastMessages();
2355 static void VM_SV_te_beam(prvm_prog_t *prog)
2357 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2358 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2359 MSG_WriteByte(&sv.datagram, TE_BEAM);
2361 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2363 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2364 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2365 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2367 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2368 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2369 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2370 SV_FlushBroadcastMessages();
2373 static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
2375 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2376 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2377 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2378 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2381 SV_FlushBroadcastMessages();
2384 static void VM_SV_te_flamejet(prvm_prog_t *prog)
2386 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2387 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2388 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2390 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2391 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2392 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2394 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2395 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2396 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2398 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2399 SV_FlushBroadcastMessages();
2402 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2403 //this function originally written by KrimZon, made shorter by LadyHavoc
2404 static void VM_SV_clientcommand(prvm_prog_t *prog)
2406 client_t *temp_client;
2408 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2410 //find client for this entity
2411 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2412 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2414 Con_Print("PF_clientcommand: entity is not a client\n");
2418 temp_client = host_client;
2419 host_client = svs.clients + i;
2420 Cmd_ExecuteString(&cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
2421 host_client = temp_client;
2424 //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)
2425 static void VM_SV_setattachment(prvm_prog_t *prog)
2427 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2428 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2429 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2432 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2434 if (e == prog->edicts)
2436 VM_Warning(prog, "setattachment: can not modify world entity\n");
2439 if (e->priv.server->free)
2441 VM_Warning(prog, "setattachment: can not modify free entity\n");
2445 if (tagentity == NULL)
2446 tagentity = prog->edicts;
2450 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2452 model = SV_GetModelFromEdict(tagentity);
2455 tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
2457 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);
2460 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));
2463 PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
2464 PRVM_serveredictfloat(e, tag_index) = tagindex;
2467 /////////////////////////////////////////
2468 // DP_MD3_TAGINFO extension coded by VorteX
2470 static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
2474 i = (int)PRVM_serveredictfloat(e, modelindex);
2475 if (i < 1 || i >= MAX_MODELS)
2478 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
2481 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2488 Matrix4x4_CreateIdentity(tag_localmatrix);
2490 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2492 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2503 void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2506 float pitchsign = 1;
2508 scale = PRVM_serveredictfloat(ent, scale);
2513 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);
2516 pitchsign = SV_GetPitchSign(prog, ent);
2517 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);
2521 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2524 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2526 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2527 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2528 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2529 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2531 *out = identitymatrix;
2535 // Warnings/errors code:
2536 // 0 - normal (everything all-right)
2539 // 3 - null or non-precached model
2540 // 4 - no tags with requested index
2541 // 5 - runaway loop at attachment chain
2542 extern cvar_t cl_bob;
2543 extern cvar_t cl_bobcycle;
2544 extern cvar_t cl_bobup;
2545 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2548 int modelindex, attachloop;
2549 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2552 *out = identitymatrix; // warnings and errors return identical matrix
2554 if (ent == prog->edicts)
2556 if (ent->priv.server->free)
2559 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
2560 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2563 model = SV_GetModelByIndex(modelindex);
2565 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2566 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2567 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2569 tagmatrix = identitymatrix;
2570 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2574 if (attachloop >= 256) // prevent runaway looping
2576 // apply transformation by child's tagindex on parent entity and then
2577 // by parent entity itself
2578 ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
2579 if (ret && attachloop == 0)
2581 SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
2582 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2583 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2584 // next iteration we process the parent entity
2585 if (PRVM_serveredictedict(ent, tag_entity))
2587 tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
2588 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
2595 // RENDER_VIEWMODEL magic
2596 if (PRVM_serveredictedict(ent, viewmodelforclient))
2598 Matrix4x4_Copy(&tagmatrix, out);
2599 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
2601 SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
2602 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2605 // Cl_bob, ported from rendering code
2606 if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
2609 // LadyHavoc: this code is *weird*, but not replacable (I think it
2610 // should be done in QC on the server, but oh well, quake is quake)
2611 // LadyHavoc: figured out bobup: the time at which the sin is at 180
2612 // degrees (which allows lengthening or squishing the peak or valley)
2613 cycle = sv.time/cl_bobcycle.value;
2614 cycle -= (int)cycle;
2615 if (cycle < cl_bobup.value)
2616 cycle = sin(M_PI * cycle / cl_bobup.value);
2618 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2619 // bob is proportional to velocity in the xy plane
2620 // (don't count Z, or jumping messes it up)
2621 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;
2622 bob = bob*0.3 + bob*0.7*cycle;
2623 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2630 //float(entity ent, string tagname) gettagindex;
2632 static void VM_SV_gettagindex(prvm_prog_t *prog)
2635 const char *tag_name;
2638 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2640 ent = PRVM_G_EDICT(OFS_PARM0);
2641 tag_name = PRVM_G_STRING(OFS_PARM1);
2643 if (ent == prog->edicts)
2645 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2648 if (ent->priv.server->free)
2650 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2655 if (!SV_GetModelFromEdict(ent))
2656 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2659 tag_index = SV_GetTagIndex(prog, ent, tag_name);
2661 if(developer_extra.integer)
2662 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2664 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2667 //vector(entity ent, float tagindex) gettaginfo;
2668 static void VM_SV_gettaginfo(prvm_prog_t *prog)
2672 matrix4x4_t tag_matrix;
2673 matrix4x4_t tag_localmatrix;
2675 const char *tagname;
2677 vec3_t forward, left, up, origin;
2678 const dp_model_t *model;
2680 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2682 e = PRVM_G_EDICT(OFS_PARM0);
2683 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2685 returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
2686 Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
2687 VectorCopy(forward, PRVM_serverglobalvector(v_forward));
2688 VectorNegate(left, PRVM_serverglobalvector(v_right));
2689 VectorCopy(up, PRVM_serverglobalvector(v_up));
2690 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
2691 model = SV_GetModelFromEdict(e);
2692 VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
2693 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
2694 VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
2695 SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2696 Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
2698 PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
2699 PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
2700 VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
2701 VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
2702 VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
2703 VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
2708 VM_Warning(prog, "gettagindex: can't affect world entity\n");
2711 VM_Warning(prog, "gettagindex: can't affect free entity\n");
2714 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2717 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2720 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2725 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2726 static void VM_SV_dropclient(prvm_prog_t *prog)
2729 client_t *oldhostclient;
2730 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2731 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2732 if (clientnum < 0 || clientnum >= svs.maxclients)
2734 VM_Warning(prog, "dropclient: not a client\n");
2737 if (!svs.clients[clientnum].active)
2739 VM_Warning(prog, "dropclient: that client slot is not connected\n");
2742 oldhostclient = host_client;
2743 host_client = svs.clients + clientnum;
2744 SV_DropClient(false);
2745 host_client = oldhostclient;
2748 //entity() spawnclient (DP_SV_BOTCLIENT)
2749 static void VM_SV_spawnclient(prvm_prog_t *prog)
2753 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2754 prog->xfunction->builtinsprofile += 2;
2756 for (i = 0;i < svs.maxclients;i++)
2758 if (!svs.clients[i].active)
2760 prog->xfunction->builtinsprofile += 100;
2761 SV_ConnectClient (i, NULL);
2762 // this has to be set or else ClientDisconnect won't be called
2763 // we assume the qc will call ClientConnect...
2764 svs.clients[i].clientconnectcalled = true;
2765 ed = PRVM_EDICT_NUM(i + 1);
2769 VM_RETURN_EDICT(ed);
2772 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2773 static void VM_SV_clienttype(prvm_prog_t *prog)
2776 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2777 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2778 if (clientnum < 0 || clientnum >= svs.maxclients)
2779 PRVM_G_FLOAT(OFS_RETURN) = 3;
2780 else if (!svs.clients[clientnum].active)
2781 PRVM_G_FLOAT(OFS_RETURN) = 0;
2782 else if (svs.clients[clientnum].netconnection)
2783 PRVM_G_FLOAT(OFS_RETURN) = 1;
2785 PRVM_G_FLOAT(OFS_RETURN) = 2;
2792 string(string key) serverkey
2795 static void VM_SV_serverkey(prvm_prog_t *prog)
2797 char string[VM_STRINGTEMP_LENGTH];
2798 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2799 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2800 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2803 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2804 static void VM_SV_setmodelindex(prvm_prog_t *prog)
2809 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2811 e = PRVM_G_EDICT(OFS_PARM0);
2812 if (e == prog->edicts)
2814 VM_Warning(prog, "setmodelindex: can not modify world entity\n");
2817 if (e->priv.server->free)
2819 VM_Warning(prog, "setmodelindex: can not modify free entity\n");
2822 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2823 if (i <= 0 || i >= MAX_MODELS)
2825 VM_Warning(prog, "setmodelindex: invalid modelindex\n");
2828 if (!sv.model_precache[i][0])
2830 VM_Warning(prog, "setmodelindex: model not precached\n");
2834 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2835 PRVM_serveredictfloat(e, modelindex) = i;
2837 mod = SV_GetModelByIndex(i);
2841 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2842 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
2844 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
2847 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
2850 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2851 static void VM_SV_modelnameforindex(prvm_prog_t *prog)
2854 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2856 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2858 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2859 if (i <= 0 || i >= MAX_MODELS)
2861 VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
2864 if (!sv.model_precache[i][0])
2866 VM_Warning(prog, "modelnameforindex: model not precached\n");
2870 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2873 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2874 static void VM_SV_particleeffectnum(prvm_prog_t *prog)
2877 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2878 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2881 PRVM_G_FLOAT(OFS_RETURN) = i;
2884 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2885 static void VM_SV_trailparticles(prvm_prog_t *prog)
2888 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2890 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2893 MSG_WriteByte(&sv.datagram, svc_trailparticles);
2894 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2895 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2896 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2897 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2898 MSG_WriteVector(&sv.datagram, start, sv.protocol);
2899 MSG_WriteVector(&sv.datagram, end, sv.protocol);
2900 SV_FlushBroadcastMessages();
2903 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
2904 static void VM_SV_pointparticles(prvm_prog_t *prog)
2906 int effectnum, count;
2908 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
2910 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2913 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2914 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
2915 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2916 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
2917 if (count == 1 && !VectorLength2(vel))
2920 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
2921 MSG_WriteShort(&sv.datagram, effectnum);
2922 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2926 // 1+2+12+12+2=29 bytes
2927 MSG_WriteByte(&sv.datagram, svc_pointparticles);
2928 MSG_WriteShort(&sv.datagram, effectnum);
2929 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2930 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
2931 MSG_WriteShort(&sv.datagram, count);
2934 SV_FlushBroadcastMessages();
2937 //PF_setpause, // void(float pause) setpause = #531;
2938 static void VM_SV_setpause(prvm_prog_t *prog) {
2940 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
2941 if (pauseValue != 0) { //pause the game
2943 sv.pausedstart = realtime;
2944 } else { //disable pause, in case it was enabled
2945 if (sv.paused != 0) {
2950 // send notification to all clients
2951 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
2952 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
2955 // #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.
2956 static void VM_SV_skel_create(prvm_prog_t *prog)
2958 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
2959 dp_model_t *model = SV_GetModelByIndex(modelindex);
2960 skeleton_t *skeleton;
2962 PRVM_G_FLOAT(OFS_RETURN) = 0;
2963 if (!model || !model->num_bones)
2965 for (i = 0;i < MAX_EDICTS;i++)
2966 if (!prog->skeletons[i])
2968 if (i == MAX_EDICTS)
2970 prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
2971 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
2972 skeleton->model = model;
2973 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
2974 // initialize to identity matrices
2975 for (i = 0;i < skeleton->model->num_bones;i++)
2976 skeleton->relativetransforms[i] = identitymatrix;
2979 // #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
2980 static void VM_SV_skel_build(prvm_prog_t *prog)
2982 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2983 skeleton_t *skeleton;
2984 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
2985 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
2986 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
2987 int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
2988 int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
2989 dp_model_t *model = SV_GetModelByIndex(modelindex);
2993 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
2994 frameblend_t frameblend[MAX_FRAMEBLENDS];
2995 matrix4x4_t bonematrix;
2997 PRVM_G_FLOAT(OFS_RETURN) = 0;
2998 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3000 firstbone = max(0, firstbone);
3001 lastbone = min(lastbone, model->num_bones - 1);
3002 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3003 VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
3004 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
3005 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3007 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3009 memset(&bonematrix, 0, sizeof(bonematrix));
3010 for (blendindex = 0;blendindex < numblends;blendindex++)
3012 Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3013 Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
3015 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
3016 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
3018 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
3021 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3022 static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
3024 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3025 skeleton_t *skeleton;
3026 PRVM_G_FLOAT(OFS_RETURN) = 0;
3027 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3029 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3032 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3033 static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
3035 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3036 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3037 skeleton_t *skeleton;
3038 PRVM_G_INT(OFS_RETURN) = 0;
3039 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3041 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3043 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
3046 // #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)
3047 static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
3049 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3050 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3051 skeleton_t *skeleton;
3052 PRVM_G_FLOAT(OFS_RETURN) = 0;
3053 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3055 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3057 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3060 // #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
3061 static void VM_SV_skel_find_bone(prvm_prog_t *prog)
3063 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3064 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3065 skeleton_t *skeleton;
3066 PRVM_G_FLOAT(OFS_RETURN) = 0;
3067 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3069 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3072 // #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)
3073 static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
3075 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3076 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3077 skeleton_t *skeleton;
3079 vec3_t forward, left, up, origin;
3080 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3081 VectorClear(PRVM_clientglobalvector(v_forward));
3082 VectorClear(PRVM_clientglobalvector(v_right));
3083 VectorClear(PRVM_clientglobalvector(v_up));
3084 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3086 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3088 matrix = skeleton->relativetransforms[bonenum];
3089 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3090 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3091 VectorNegate(left, PRVM_clientglobalvector(v_right));
3092 VectorCopy(up, PRVM_clientglobalvector(v_up));
3093 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3096 // #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)
3097 static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
3099 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3100 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3101 skeleton_t *skeleton;
3104 vec3_t forward, left, up, origin;
3105 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3106 VectorClear(PRVM_clientglobalvector(v_forward));
3107 VectorClear(PRVM_clientglobalvector(v_right));
3108 VectorClear(PRVM_clientglobalvector(v_up));
3109 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3111 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3113 matrix = skeleton->relativetransforms[bonenum];
3114 // convert to absolute
3115 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3118 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3120 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3121 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3122 VectorNegate(left, PRVM_clientglobalvector(v_right));
3123 VectorCopy(up, PRVM_clientglobalvector(v_up));
3124 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3127 // #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)
3128 static void VM_SV_skel_set_bone(prvm_prog_t *prog)
3130 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3131 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3132 vec3_t forward, left, up, origin;
3133 skeleton_t *skeleton;
3135 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3137 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3139 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3140 VectorNegate(PRVM_clientglobalvector(v_right), left);
3141 VectorCopy(PRVM_clientglobalvector(v_up), up);
3142 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3143 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3144 skeleton->relativetransforms[bonenum] = matrix;
3147 // #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)
3148 static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
3150 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3151 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3152 vec3_t forward, left, up, origin;
3153 skeleton_t *skeleton;
3156 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3158 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3160 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3161 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3162 VectorNegate(PRVM_clientglobalvector(v_right), left);
3163 VectorCopy(PRVM_clientglobalvector(v_up), up);
3164 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3165 temp = skeleton->relativetransforms[bonenum];
3166 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3169 // #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)
3170 static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
3172 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3173 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3174 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3176 vec3_t forward, left, up, origin;
3177 skeleton_t *skeleton;
3180 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3182 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3183 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3184 VectorNegate(PRVM_clientglobalvector(v_right), left);
3185 VectorCopy(PRVM_clientglobalvector(v_up), up);
3186 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3187 firstbone = max(0, firstbone);
3188 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3189 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3191 temp = skeleton->relativetransforms[bonenum];
3192 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3196 // #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
3197 static void VM_SV_skel_copybones(prvm_prog_t *prog)
3199 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3200 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3201 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3202 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3204 skeleton_t *skeletondst;
3205 skeleton_t *skeletonsrc;
3206 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3208 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3210 firstbone = max(0, firstbone);
3211 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3212 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3213 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3214 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3217 // #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)
3218 static void VM_SV_skel_delete(prvm_prog_t *prog)
3220 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3221 skeleton_t *skeleton;
3222 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3225 prog->skeletons[skeletonindex] = NULL;
3228 // #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
3229 static void VM_SV_frameforname(prvm_prog_t *prog)
3231 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3232 dp_model_t *model = SV_GetModelByIndex(modelindex);
3233 const char *name = PRVM_G_STRING(OFS_PARM1);
3235 PRVM_G_FLOAT(OFS_RETURN) = -1;
3236 if (!model || !model->animscenes)
3238 for (i = 0;i < model->numframes;i++)
3240 if (!strcasecmp(model->animscenes[i].name, name))
3242 PRVM_G_FLOAT(OFS_RETURN) = i;
3248 // #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.
3249 static void VM_SV_frameduration(prvm_prog_t *prog)
3251 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3252 dp_model_t *model = SV_GetModelByIndex(modelindex);
3253 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3254 PRVM_G_FLOAT(OFS_RETURN) = 0;
3255 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3257 if (model->animscenes[framenum].framerate)
3258 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3262 prvm_builtin_t vm_sv_builtins[] = {
3263 NULL, // #0 NULL function (not callable) (QUAKE)
3264 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3265 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3266 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3267 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3268 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3269 VM_break, // #6 void() break (QUAKE)
3270 VM_random, // #7 float() random (QUAKE)
3271 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3272 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3273 VM_error, // #10 void(string e) error (QUAKE)
3274 VM_objerror, // #11 void(string e) objerror (QUAKE)
3275 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3276 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3277 VM_spawn, // #14 entity() spawn (QUAKE)
3278 VM_remove, // #15 void(entity e) remove (QUAKE)
3279 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3280 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3281 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3282 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3283 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3284 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3285 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3286 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3287 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3288 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3289 VM_ftos, // #26 string(float f) ftos (QUAKE)
3290 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3291 VM_coredump, // #28 void() coredump (QUAKE)
3292 VM_traceon, // #29 void() traceon (QUAKE)
3293 VM_traceoff, // #30 void() traceoff (QUAKE)
3294 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3295 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3296 NULL, // #33 (QUAKE)
3297 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3298 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3299 VM_rint, // #36 float(float v) rint (QUAKE)
3300 VM_floor, // #37 float(float v) floor (QUAKE)
3301 VM_ceil, // #38 float(float v) ceil (QUAKE)
3302 NULL, // #39 (QUAKE)
3303 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3304 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3305 NULL, // #42 (QUAKE)
3306 VM_fabs, // #43 float(float f) fabs (QUAKE)
3307 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3308 VM_cvar, // #45 float(string s) cvar (QUAKE)
3309 VM_localcmd_server, // #46 void(string s) localcmd (QUAKE)
3310 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3311 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3312 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3313 NULL, // #50 (QUAKE)
3314 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3315 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3316 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3317 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3318 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3319 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3320 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3321 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3322 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3323 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3324 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3325 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3326 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3327 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3328 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3329 NULL, // #66 (QUAKE)
3330 VM_SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3331 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3332 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3333 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3334 NULL, // #71 (QUAKE)
3335 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3336 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3337 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3338 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3339 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3340 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3341 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3342 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3343 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3344 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3345 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3346 NULL, // #83 (QUAKE)
3347 NULL, // #84 (QUAKE)
3348 NULL, // #85 (QUAKE)
3349 NULL, // #86 (QUAKE)
3350 NULL, // #87 (QUAKE)
3351 NULL, // #88 (QUAKE)
3352 NULL, // #89 (QUAKE)
3353 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3354 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3355 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3356 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3357 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3358 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3359 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3360 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3361 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3362 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3363 // FrikaC and Telejano range #100-#199
3374 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3375 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3376 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3377 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3378 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3379 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3380 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3381 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3382 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3383 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3464 // FTEQW range #200-#299
3483 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3486 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3487 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3488 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3489 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3490 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3491 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3492 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3493 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3494 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3495 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3497 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3505 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3528 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.
3529 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
3530 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3531 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3532 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)
3533 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
3534 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)
3535 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)
3536 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)
3537 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)
3538 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)
3539 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
3540 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)
3541 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
3542 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.
3565 // CSQC range #300-#399
3566 NULL, // #300 void() clearscene (EXT_CSQC)
3567 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3568 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3569 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3570 NULL, // #304 void() renderscene (EXT_CSQC)
3571 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3572 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3573 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3574 NULL, // #308 void() R_EndPolygon
3576 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3577 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3581 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3582 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3583 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3584 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3585 NULL, // #319 void(string name) freepic (EXT_CSQC)
3586 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3587 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3588 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3589 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3590 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3591 NULL, // #325 void(void) drawresetcliparea
3596 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3597 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3598 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3599 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3600 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3601 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3602 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3603 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3604 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3605 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3606 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3607 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3608 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3609 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3610 NULL, // #344 vector() getmousepos (EXT_CSQC)
3611 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3612 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3613 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3614 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3615 NULL, // #349 float() isdemo (EXT_CSQC)
3616 VM_isserver, // #350 float() isserver (EXT_CSQC)
3617 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3618 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3619 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3620 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3626 NULL, // #360 float() readbyte (EXT_CSQC)
3627 NULL, // #361 float() readchar (EXT_CSQC)
3628 NULL, // #362 float() readshort (EXT_CSQC)
3629 NULL, // #363 float() readlong (EXT_CSQC)
3630 NULL, // #364 float() readcoord (EXT_CSQC)
3631 NULL, // #365 float() readangle (EXT_CSQC)
3632 NULL, // #366 string() readstring (EXT_CSQC)
3633 NULL, // #367 float() readfloat (EXT_CSQC)
3666 // LadyHavoc's range #400-#499
3667 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3668 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3669 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3670 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3671 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3672 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3673 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3674 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3675 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)
3676 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3677 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3678 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3679 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3680 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3681 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3682 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3683 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3684 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3685 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3686 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3687 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3688 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3689 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3690 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3691 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3692 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3693 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3694 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3695 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3696 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3697 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3698 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3699 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3700 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3701 VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3702 VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3703 VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3704 VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3705 VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3706 VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3707 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3708 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3709 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3710 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3711 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3712 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3713 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3714 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3715 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3716 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3717 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3718 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3719 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3720 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3721 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3722 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3723 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3724 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3726 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3727 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3728 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3729 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3730 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3731 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3732 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3733 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3734 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3735 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3736 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3738 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3739 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3740 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3741 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3742 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3743 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3744 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3745 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3746 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3747 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3748 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3749 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3750 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3751 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3752 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3753 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3761 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3762 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3763 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3764 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3765 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3766 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3767 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3768 VM_SV_WritePicture, // #501
3770 VM_whichpack, // #503 string(string) whichpack = #503;
3777 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3778 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3779 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3780 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)
3781 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3782 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3783 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3784 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3785 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3786 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3796 VM_loadfromdata, // #529
3797 VM_loadfromfile, // #530
3798 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3800 VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
3801 VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
3802 VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
3803 VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
3804 VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
3805 VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
3807 VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
3808 VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
3809 VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
3872 VM_callfunction, // #605
3873 VM_writetofile, // #606
3874 VM_isfunction, // #607
3880 VM_parseentitydata, // #613
3891 VM_SV_getextresponse, // #624 string getextresponse(void)
3894 VM_sprintf, // #627 string sprintf(string format, ...)
3895 VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
3896 VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
3906 VM_digest_hex, // #639
3909 VM_coverage, // #642
3917 // WRATH range (#650-#???)
3918 VM_fcopy, // #650 float(string fnfrom, string fnto) fcopy (EXT_WRATH)
3919 VM_frename, // #651 float (string fnold, string fnnew) frename (EXT_WRATH)
3920 VM_fremove, // #652 float (string fname) fremove (EXT_WRATH)
3921 VM_fexists, // #653 float (string fname) fexists (EXT_WRATH)
3922 VM_rmtree, // #654 float (string path) rmtree (EXT_WRATH)
3923 VM_SV_walkmovedist, // #655 float (float yaw, float dist[, float settrace]) walkmovedist (EXT_WRATH)
4021 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4023 void SVVM_init_cmd(prvm_prog_t *prog)
4028 void SVVM_reset_cmd(prvm_prog_t *prog)
4030 World_End(&sv.world);
4032 if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
4034 func_t s = PRVM_serverfunction(SV_Shutdown);
4035 PRVM_serverglobalfloat(time) = sv.time;
4036 PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
4037 prog->ExecuteProgram(prog, s,"SV_Shutdown() required");