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",
231 "DP_QC_FS_SEARCH_PACKFILE",
234 //"EXT_CSQC" // not ready yet
241 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.
243 setorigin (entity, origin)
246 static void VM_SV_setorigin(prvm_prog_t *prog)
250 VM_SAFEPARMCOUNT(2, VM_SV_setorigin);
252 e = PRVM_G_EDICT(OFS_PARM0);
253 if (e == prog->edicts)
255 VM_Warning(prog, "setorigin: can not modify world entity\n");
260 VM_Warning(prog, "setorigin: can not modify free entity\n");
263 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), PRVM_serveredictvector(e, origin));
264 if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
265 e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
269 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
270 static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max, qbool rotate)
274 for (i=0 ; i<3 ; i++)
276 prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
278 // set derived values
279 VectorCopy (min, PRVM_serveredictvector(e, mins));
280 VectorCopy (max, PRVM_serveredictvector(e, maxs));
281 VectorSubtract (max, min, PRVM_serveredictvector(e, size));
290 the size box is rotated by the current angle
291 LadyHavoc: no it isn't...
293 setsize (entity, minvector, maxvector)
296 static void VM_SV_setsize(prvm_prog_t *prog)
301 VM_SAFEPARMCOUNT(3, VM_SV_setsize);
303 e = PRVM_G_EDICT(OFS_PARM0);
304 if (e == prog->edicts)
306 VM_Warning(prog, "setsize: can not modify world entity\n");
311 VM_Warning(prog, "setsize: can not modify free entity\n");
314 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
315 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
316 SetMinMaxSize(prog, e, mins, maxs, false);
324 setmodel(entity, model)
327 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
328 static void VM_SV_setmodel(prvm_prog_t *prog)
334 VM_SAFEPARMCOUNT(2, VM_SV_setmodel);
336 e = PRVM_G_EDICT(OFS_PARM0);
337 if (e == prog->edicts)
339 VM_Warning(prog, "setmodel: can not modify world entity\n");
344 VM_Warning(prog, "setmodel: can not modify free entity\n");
347 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
348 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
349 PRVM_serveredictfloat(e, modelindex) = i;
351 mod = SV_GetModelByIndex(i);
355 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
356 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
358 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
361 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
368 single print to a specific client
370 sprint(clientent, value)
373 static void VM_SV_sprint(prvm_prog_t *prog)
377 char string[VM_STRINGTEMP_LENGTH];
379 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
381 VM_VarString(prog, 1, string, sizeof(string));
383 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
384 // LadyHavoc: div0 requested that sprintto world operate like print
391 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
393 VM_Warning(prog, "tried to centerprint to a non-client\n");
397 client = svs.clients + entnum-1;
398 if (!client->netconnection)
401 MSG_WriteChar(&client->netconnection->message,svc_print);
402 MSG_WriteString(&client->netconnection->message, string);
410 single print to a specific client
412 centerprint(clientent, value)
415 static void VM_SV_centerprint(prvm_prog_t *prog)
419 char string[VM_STRINGTEMP_LENGTH];
421 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
423 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
425 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
427 VM_Warning(prog, "tried to centerprint to a non-client\n");
431 client = svs.clients + entnum-1;
432 if (!client->netconnection)
435 VM_VarString(prog, 1, string, sizeof(string));
436 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
437 MSG_WriteString(&client->netconnection->message, string);
444 particle(origin, color, count)
447 static void VM_SV_particle(prvm_prog_t *prog)
453 VM_SAFEPARMCOUNT(4, VM_SV_particle);
455 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
456 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
457 color = (int)PRVM_G_FLOAT(OFS_PARM2);
458 count = (int)PRVM_G_FLOAT(OFS_PARM3);
459 SV_StartParticle (org, dir, color, count);
469 static void VM_SV_ambientsound(prvm_prog_t *prog)
473 prvm_vec_t vol, attenuation;
476 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
478 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
479 samp = PRVM_G_STRING(OFS_PARM1);
480 vol = PRVM_G_FLOAT(OFS_PARM2);
481 attenuation = PRVM_G_FLOAT(OFS_PARM3);
483 // check to see if samp was properly precached
484 soundnum = SV_SoundIndex(samp, 1);
492 if(sv.protocol == PROTOCOL_NEHAHRABJP)
495 // add an svc_spawnambient command to the level signon packet
498 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
500 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
502 MSG_WriteVector(&sv.signon, pos, sv.protocol);
504 if (large || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
505 MSG_WriteShort (&sv.signon, soundnum);
507 MSG_WriteByte (&sv.signon, soundnum);
509 MSG_WriteByte (&sv.signon, (int)(vol*255));
510 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
518 Each entity can have eight independant sound sources, like voice,
521 Channel 0 is an auto-allocate channel, the others override anything
522 already running on that entity/channel pair.
524 An attenuation of 0 will play full volume everywhere in the level.
525 Larger attenuations will drop off.
527 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
530 static void VM_SV_sound(prvm_prog_t *prog)
534 prvm_edict_t *entity;
540 VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
542 entity = PRVM_G_EDICT(OFS_PARM0);
543 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
544 sample = PRVM_G_STRING(OFS_PARM2);
545 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
548 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
552 attenuation = PRVM_G_FLOAT(OFS_PARM4);
556 pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
561 if(channel >= 8 && channel <= 15) // weird QW feature
563 flags |= CHANNELFLAG_RELIABLE;
569 // LadyHavoc: we only let the qc set certain flags, others are off-limits
570 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
573 if (nvolume < 0 || nvolume > 255)
575 VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
579 if (attenuation < 0 || attenuation > 4)
581 VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
585 channel = CHAN_USER2ENGINE(channel);
587 if (!IS_CHAN(channel))
589 VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
593 SV_StartSound (entity, channel, sample, nvolume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange);
600 Follows the same logic as VM_SV_sound, except instead of
601 an entity, an origin for the sound is provided, and channel
602 is omitted (since no entity is being tracked).
606 static void VM_SV_pointsound(prvm_prog_t *prog)
614 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
616 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
617 sample = PRVM_G_STRING(OFS_PARM1);
618 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
619 attenuation = PRVM_G_FLOAT(OFS_PARM3);
620 pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
622 if (nvolume < 0 || nvolume > 255)
624 VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
628 if (attenuation < 0 || attenuation > 4)
630 VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
634 SV_StartPointSound (org, sample, nvolume, attenuation, pitchchange);
641 Used for use tracing and shot targeting
642 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
643 if the tryents flag is set.
645 traceline (vector1, vector2, movetype, ignore)
648 static void VM_SV_traceline(prvm_prog_t *prog)
655 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
657 prog->xfunction->builtinsprofile += 30;
659 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
660 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
661 move = (int)PRVM_G_FLOAT(OFS_PARM2);
662 ent = PRVM_G_EDICT(OFS_PARM3);
664 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]))
665 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));
667 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value);
669 VM_SetTraceGlobals(prog, &trace);
677 Used for use tracing and shot targeting
678 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
679 if the tryents flag is set.
681 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
684 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
685 static void VM_SV_tracebox(prvm_prog_t *prog)
687 vec3_t v1, v2, m1, m2;
692 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
694 prog->xfunction->builtinsprofile += 30;
696 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
697 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
698 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
699 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
700 move = (int)PRVM_G_FLOAT(OFS_PARM4);
701 ent = PRVM_G_EDICT(OFS_PARM5);
703 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]))
704 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));
706 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value);
708 VM_SetTraceGlobals(prog, &trace);
711 static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
715 vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
716 vec3_t original_origin;
717 vec3_t original_velocity;
718 vec3_t original_angles;
719 vec3_t original_avelocity;
722 VectorCopy(PRVM_serveredictvector(tossent, origin) , original_origin );
723 VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
724 VectorCopy(PRVM_serveredictvector(tossent, angles) , original_angles );
725 VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
727 gravity = PRVM_serveredictfloat(tossent, gravity);
730 gravity *= sv_gravity.value * 0.025;
732 for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
734 SV_CheckVelocity (tossent);
735 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
736 VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
737 VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
738 VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
739 VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
740 VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
741 VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
742 trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value);
743 VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
744 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
746 if (trace.fraction < 1)
750 VectorCopy(original_origin , PRVM_serveredictvector(tossent, origin) );
751 VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
752 VectorCopy(original_angles , PRVM_serveredictvector(tossent, angles) );
753 VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
758 static void VM_SV_tracetoss(prvm_prog_t *prog)
762 prvm_edict_t *ignore;
764 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
766 prog->xfunction->builtinsprofile += 600;
768 ent = PRVM_G_EDICT(OFS_PARM0);
769 if (ent == prog->edicts)
771 VM_Warning(prog, "tracetoss: can not use world entity\n");
774 ignore = PRVM_G_EDICT(OFS_PARM1);
776 trace = SV_Trace_Toss(prog, ent, ignore);
778 VM_SetTraceGlobals(prog, &trace);
781 //============================================================================
783 static int checkpvsbytes;
784 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
786 static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
792 // cycle to the next one
794 check = bound(1, check, svs.maxclients);
795 if (check == svs.maxclients)
803 prog->xfunction->builtinsprofile++;
805 if (i == svs.maxclients+1)
807 // look up the client's edict
808 ent = PRVM_EDICT_NUM(i);
809 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
810 if (i != check && (ent->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
812 // found a valid client (possibly the same one again)
816 // get the PVS for the entity
817 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
819 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
820 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
829 Returns a client (or object that has a client enemy) that would be a
832 If there is more than one valid option, they are cycled each frame
834 If (self.origin + self.viewofs) is not in the PVS of the current target,
835 it is not returned at all.
840 int c_invis, c_notvis;
841 static void VM_SV_checkclient(prvm_prog_t *prog)
843 prvm_edict_t *ent, *self;
846 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
848 // find a new check if on a new frame
849 if (sv.time - sv.lastchecktime >= 0.1)
851 sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
852 sv.lastchecktime = sv.time;
855 // return check if it might be visible
856 ent = PRVM_EDICT_NUM(sv.lastcheck);
857 if (ent->free || PRVM_serveredictfloat(ent, health) <= 0)
859 VM_RETURN_EDICT(prog->edicts);
863 // if current entity can't possibly see the check entity, return 0
864 self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
865 VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
866 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
869 VM_RETURN_EDICT(prog->edicts);
873 // might be able to see it
875 VM_RETURN_EDICT(ent);
878 //============================================================================
884 Checks if an entity is in a point's PVS.
885 Should be fast but can be inexact.
887 float checkpvs(vector viewpos, entity viewee) = #240;
890 static void VM_SV_checkpvs(prvm_prog_t *prog)
892 vec3_t viewpos, absmin, absmax;
893 prvm_edict_t *viewee;
898 unsigned char fatpvs[MAX_MAP_LEAFS/8];
901 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
902 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
903 viewee = PRVM_G_EDICT(OFS_PARM1);
907 VM_Warning(prog, "checkpvs: can not check free entity\n");
908 PRVM_G_FLOAT(OFS_RETURN) = 4;
913 if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
915 // no PVS support on this worldmodel... darn
916 PRVM_G_FLOAT(OFS_RETURN) = 3;
919 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
922 // viewpos isn't in any PVS... darn
923 PRVM_G_FLOAT(OFS_RETURN) = 2;
926 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
927 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
928 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
930 // using fat PVS like FTEQW does (slow)
931 if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
933 // no PVS support on this worldmodel... darn
934 PRVM_G_FLOAT(OFS_RETURN) = 3;
937 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
940 // viewpos isn't in any PVS... darn
941 PRVM_G_FLOAT(OFS_RETURN) = 2;
944 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
945 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
946 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
955 Sends text over to the client's execution buffer
957 stuffcmd (clientent, value, ...)
960 static void VM_SV_stuffcmd(prvm_prog_t *prog)
964 char string[VM_STRINGTEMP_LENGTH];
966 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
968 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
969 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
971 VM_Warning(prog, "Can't stuffcmd to a non-client\n");
975 VM_VarString(prog, 1, string, sizeof(string));
978 host_client = svs.clients + entnum-1;
979 SV_ClientCommands ("%s", string);
987 Returns a chain of entities that have origins within a spherical area
989 findradius (origin, radius)
992 static void VM_SV_findradius(prvm_prog_t *prog)
994 prvm_edict_t *ent, *chain;
995 vec_t radius, radius2;
996 vec3_t org, eorg, mins, maxs;
999 static prvm_edict_t *touchedicts[MAX_EDICTS];
1002 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
1005 chainfield = PRVM_G_INT(OFS_PARM2);
1007 chainfield = prog->fieldoffsets.chain;
1009 prog->error_cmd("VM_SV_findradius: %s doesnt have the specified chain field !", prog->name);
1011 chain = (prvm_edict_t *)prog->edicts;
1013 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1014 radius = PRVM_G_FLOAT(OFS_PARM1);
1015 radius2 = radius * radius;
1017 mins[0] = org[0] - (radius + 1);
1018 mins[1] = org[1] - (radius + 1);
1019 mins[2] = org[2] - (radius + 1);
1020 maxs[0] = org[0] + (radius + 1);
1021 maxs[1] = org[1] + (radius + 1);
1022 maxs[2] = org[2] + (radius + 1);
1023 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1024 if (numtouchedicts > MAX_EDICTS)
1026 // this never happens
1027 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1028 numtouchedicts = MAX_EDICTS;
1030 for (i = 0;i < numtouchedicts;i++)
1032 ent = touchedicts[i];
1033 prog->xfunction->builtinsprofile++;
1034 // Quake did not return non-solid entities but darkplaces does
1035 // (note: this is the reason you can't blow up fallen zombies)
1036 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1038 // LadyHavoc: compare against bounding box rather than center so it
1039 // doesn't miss large objects, and use DotProduct instead of Length
1040 // for a major speedup
1041 VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
1042 if (sv_gameplayfix_findradiusdistancetobox.integer)
1044 eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
1045 eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
1046 eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
1049 VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
1050 if (DotProduct(eorg, eorg) < radius2)
1052 PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
1057 VM_RETURN_EDICT(chain);
1064 Returns a chain of entities that are touching a box (a simpler findradius); supports DP_QC_FINDCHAIN_TOFIELD
1066 findbox (mins, maxs)
1069 static void VM_SV_findbox(prvm_prog_t *prog)
1071 prvm_edict_t *chain;
1072 int i, numtouchedicts;
1073 static prvm_edict_t *touchedicts[MAX_EDICTS];
1076 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findbox);
1079 chainfield = PRVM_G_INT(OFS_PARM2);
1081 chainfield = prog->fieldoffsets.chain;
1083 prog->error_cmd("VM_SV_findbox: %s doesnt have the specified chain field !", prog->name);
1085 chain = (prvm_edict_t *)prog->edicts;
1087 numtouchedicts = SV_EntitiesInBox(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), MAX_EDICTS, touchedicts);
1088 if (numtouchedicts > MAX_EDICTS)
1090 // this never happens
1091 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1092 numtouchedicts = MAX_EDICTS;
1094 for (i = 0; i < numtouchedicts; ++i)
1096 prog->xfunction->builtinsprofile++;
1097 PRVM_EDICTFIELDEDICT(touchedicts[i], chainfield) = PRVM_EDICT_TO_PROG(chain);
1098 chain = touchedicts[i];
1101 VM_RETURN_EDICT(chain);
1104 static void VM_SV_precache_sound(prvm_prog_t *prog)
1106 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1107 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1110 static void VM_SV_precache_model(prvm_prog_t *prog)
1112 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1113 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1114 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1121 float(float yaw, float dist[, settrace]) walkmove
1124 static void VM_SV_walkmove(prvm_prog_t *prog)
1133 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1135 // assume failure if it returns early
1136 PRVM_G_FLOAT(OFS_RETURN) = 0;
1138 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1139 if (ent == prog->edicts)
1141 VM_Warning(prog, "walkmove: can not modify world entity\n");
1146 VM_Warning(prog, "walkmove: can not modify free entity\n");
1149 yaw = PRVM_G_FLOAT(OFS_PARM0);
1150 dist = PRVM_G_FLOAT(OFS_PARM1);
1151 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1153 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1156 yaw = yaw*M_PI*2 / 360;
1158 move[0] = cos(yaw)*dist;
1159 move[1] = sin(yaw)*dist;
1162 // save program state, because SV_movestep may call other progs
1163 oldf = prog->xfunction;
1164 oldself = PRVM_serverglobaledict(self);
1166 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1169 // restore program state
1170 prog->xfunction = oldf;
1171 PRVM_serverglobaledict(self) = oldself;
1181 inline static qbool droptofloor_bsp_failcond(trace_t *trace)
1183 if (sv.worldmodel->brush.isq3bsp || sv.worldmodel->brush.isq2bsp)
1184 return trace->startsolid;
1186 return trace->allsolid || trace->fraction == 1;
1188 static void VM_SV_droptofloor(prvm_prog_t *prog)
1194 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1196 // assume failure if it returns early
1197 PRVM_G_FLOAT(OFS_RETURN) = 0;
1199 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1200 if (ent == prog->edicts)
1202 VM_Warning(prog, "droptofloor: can not modify world entity\n");
1207 VM_Warning(prog, "droptofloor: can not modify free entity\n");
1211 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1213 int n = PHYS_NudgeOutOfSolid(prog, ent);
1215 VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid_nudgetocorrect COULD NOT FIX badly placed entity \"%s\" before drop\n", PRVM_gameedictvector(ent, origin)[0], PRVM_gameedictvector(ent, origin)[1], PRVM_gameedictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
1217 VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid_nudgetocorrect FIXED badly placed entity \"%s\" before drop\n", PRVM_gameedictvector(ent, origin)[0], PRVM_gameedictvector(ent, origin)[1], PRVM_gameedictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
1220 VectorCopy (PRVM_serveredictvector(ent, origin), end);
1221 if (sv.worldmodel->brush.isq3bsp)
1223 else if (sv.worldmodel->brush.isq2bsp)
1226 end[2] -= 256; // Quake, QuakeWorld
1228 /* bones_was_here: not using SV_GenericHitSuperContentsMask(ent) anymore because it was setting:
1229 * items: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY
1230 * monsters: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP
1231 * explobox: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE
1232 * which caused (startsolid == true) when, for example, a health was touching a monster.
1233 * Changing MOVE_NORMAL also fixes that, but other engines are using MOVE_NORMAL here.
1235 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1236 if (droptofloor_bsp_failcond(&trace))
1238 if (sv_gameplayfix_droptofloorstartsolid.integer)
1242 offset[0] = 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]);
1243 offset[1] = 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]);
1244 offset[2] = PRVM_serveredictvector(ent, mins)[2];
1245 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
1246 VectorAdd(end, offset, end);
1248 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1249 if (droptofloor_bsp_failcond(&trace))
1251 VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid COULD NOT FIX badly placed entity \"%s\"\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
1254 VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid FIXED badly placed entity \"%s\"\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
1255 VectorSubtract(trace.endpos, offset, PRVM_serveredictvector(ent, origin));
1257 // only because we dropped it without considering its bbox
1258 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1259 PHYS_NudgeOutOfSolid(prog, ent);
1263 VM_Warning(prog, "droptofloor at \"%f %f %f\": badly placed entity \"%s\", startsolid: %d allsolid: %d\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)), trace.startsolid, trace.allsolid);
1268 VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
1271 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1272 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1273 PRVM_G_FLOAT(OFS_RETURN) = 1;
1274 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1275 ent->priv.server->suspendedinairflag = true;
1282 void(float style, string value) lightstyle
1285 static void VM_SV_lightstyle(prvm_prog_t *prog)
1292 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1294 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1295 val = PRVM_G_STRING(OFS_PARM1);
1297 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1298 prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
1301 // change the string in sv
1302 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1304 // send message to all clients on this server
1305 if (sv.state != ss_active)
1308 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1310 if (client->active && client->netconnection)
1312 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1313 MSG_WriteChar (&client->netconnection->message,style);
1314 MSG_WriteString (&client->netconnection->message, val);
1324 static void VM_SV_checkbottom(prvm_prog_t *prog)
1326 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1327 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1335 static void VM_SV_pointcontents(prvm_prog_t *prog)
1338 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1339 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
1340 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(point));
1347 Pick a vector for the player to shoot along
1348 vector aim(entity, missilespeed)
1351 static void VM_SV_aim(prvm_prog_t *prog)
1353 prvm_edict_t *ent, *check, *bestent;
1354 vec3_t start, dir, end, bestdir;
1357 float dist, bestdist;
1360 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1362 // assume failure if it returns early
1363 VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1364 // if sv_aim is so high it can't possibly accept anything, skip out early
1365 if (sv_aim.value >= 1)
1368 ent = PRVM_G_EDICT(OFS_PARM0);
1369 if (ent == prog->edicts)
1371 VM_Warning(prog, "aim: can not use world entity\n");
1376 VM_Warning(prog, "aim: can not use free entity\n");
1379 //speed = PRVM_G_FLOAT(OFS_PARM1);
1381 VectorCopy (PRVM_serveredictvector(ent, origin), start);
1384 // try sending a trace straight
1385 VectorCopy (PRVM_serverglobalvector(v_forward), dir);
1386 VectorMA (start, 2048, dir, end);
1387 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1388 if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
1389 && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
1391 VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1396 // try all possible entities
1397 VectorCopy (dir, bestdir);
1398 bestdist = sv_aim.value;
1401 check = PRVM_NEXT_EDICT(prog->edicts);
1402 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1404 prog->xfunction->builtinsprofile++;
1405 if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
1409 if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
1410 continue; // don't aim at teammate
1411 for (j=0 ; j<3 ; j++)
1412 end[j] = PRVM_serveredictvector(check, origin)[j]
1413 + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
1414 VectorSubtract (end, start, dir);
1415 VectorNormalize (dir);
1416 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1417 if (dist < bestdist)
1418 continue; // to far to turn
1419 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1420 if (tr.ent == check)
1421 { // can shoot at this one
1429 VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
1430 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1431 VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
1433 VectorNormalize (end);
1434 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1438 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1443 ===============================================================================
1447 ===============================================================================
1450 #define MSG_BROADCAST 0 // unreliable to all
1451 #define MSG_ONE 1 // reliable to one (msg_entity)
1452 #define MSG_ALL 2 // reliable to all
1453 #define MSG_INIT 3 // write to the init string
1454 #define MSG_ENTITY 5
1456 static sizebuf_t *WriteDest(prvm_prog_t *prog)
1462 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1466 return &sv.datagram;
1469 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
1470 entnum = PRVM_NUM_FOR_EDICT(ent);
1471 if (entnum < 1 || entnum > svs.maxclients)
1473 VM_Warning(prog, "WriteDest: tried to write to non-client\n");
1474 return &sv.reliable_datagram;
1476 else if (!svs.clients[entnum-1].active)
1478 VM_Warning(prog, "WriteDest: tried to write to a disconnected client\n");
1479 return &sv.reliable_datagram;
1481 else if (!svs.clients[entnum-1].netconnection)
1483 VM_Warning(prog, "WriteDest: tried to write to a bot client\n");
1484 return &sv.reliable_datagram;
1487 return &svs.clients[entnum-1].netconnection->message;
1490 VM_Warning(prog, "WriteDest: bad destination\n");
1492 return &sv.reliable_datagram;
1498 return sv.writeentitiestoclient_msg;
1504 static void VM_SV_WriteByte(prvm_prog_t *prog)
1506 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1507 MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1510 static void VM_SV_WriteChar(prvm_prog_t *prog)
1512 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1513 MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1516 static void VM_SV_WriteShort(prvm_prog_t *prog)
1518 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1519 MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1522 static void VM_SV_WriteLong(prvm_prog_t *prog)
1524 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1525 MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1528 static void VM_SV_WriteAngle(prvm_prog_t *prog)
1530 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1531 MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1534 static void VM_SV_WriteCoord(prvm_prog_t *prog)
1536 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1537 MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1540 static void VM_SV_WriteString(prvm_prog_t *prog)
1542 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1543 MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1546 static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
1548 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1549 MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1553 static void VM_SV_WriteEntity(prvm_prog_t *prog)
1555 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1556 MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
1559 // writes a picture as at most size bytes of data
1561 // IMGNAME \0 SIZE(short) IMGDATA
1562 // if failed to read/compress:
1564 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1565 static void VM_SV_WritePicture(prvm_prog_t *prog)
1567 const char *imgname;
1571 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1573 imgname = PRVM_G_STRING(OFS_PARM1);
1574 size = (size_t) PRVM_G_FLOAT(OFS_PARM2);
1578 MSG_WriteString(WriteDest(prog), imgname);
1579 if(Image_Compress(imgname, size, &buf, &size))
1582 MSG_WriteShort(WriteDest(prog), (int)size);
1583 SZ_Write(WriteDest(prog), (unsigned char *) buf, (int)size);
1588 MSG_WriteShort(WriteDest(prog), 0);
1592 //////////////////////////////////////////////////////////
1594 static void VM_SV_makestatic(prvm_prog_t *prog)
1599 // allow 0 parameters due to an id1 qc bug in which this function is used
1600 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1601 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1603 if (prog->argc >= 1)
1604 ent = PRVM_G_EDICT(OFS_PARM0);
1606 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1607 if (ent == prog->edicts)
1609 VM_Warning(prog, "makestatic: can not modify world entity\n");
1614 VM_Warning(prog, "makestatic: can not modify free entity\n");
1619 if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
1622 if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1624 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1625 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1626 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1630 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1631 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1632 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1636 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1637 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1638 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1641 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
1642 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
1643 for (i=0 ; i<3 ; i++)
1645 MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
1646 MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
1649 // throw the entity away now
1650 PRVM_ED_Free(prog, ent);
1653 //=============================================================================
1660 static void VM_SV_setspawnparms(prvm_prog_t *prog)
1666 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1668 ent = PRVM_G_EDICT(OFS_PARM0);
1669 i = PRVM_NUM_FOR_EDICT(ent);
1670 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1672 Con_Print("tried to setspawnparms on a non-client\n");
1676 // copy spawn parms out of the client_t
1677 client = svs.clients + i-1;
1678 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1679 (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
1686 Returns a color vector indicating the lighting at the requested point.
1688 (Internal Operation note: actually measures the light beneath the point, just like
1689 the model lighting on the client)
1694 static void VM_SV_getlight(prvm_prog_t *prog)
1696 vec3_t ambientcolor, diffusecolor, diffusenormal;
1698 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1699 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
1700 VectorClear(ambientcolor);
1701 VectorClear(diffusecolor);
1702 VectorClear(diffusenormal);
1703 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1704 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1705 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1710 unsigned char type; // 1/2/8 or 0 to indicate unused
1714 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)
1715 static int vm_customstats_last;
1717 void VM_CustomStats_Clear (void)
1719 memset(vm_customstats, 0, sizeof(vm_customstats));
1720 vm_customstats_last = -1;
1723 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1725 prvm_prog_t *prog = SVVM_prog;
1733 for(i=MIN_VM_STAT; i<=vm_customstats_last ;i++)
1735 if(!vm_customstats[i].type)
1737 switch(vm_customstats[i].type)
1739 //string as 16 bytes
1742 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1743 stats[i] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1744 stats[i+1] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1745 stats[i+2] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1746 stats[i+3] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1748 //float field sent as-is
1750 // 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
1751 u.f = PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1754 //integer value of float field
1756 stats[i] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1764 extern cvar_t sv_gameplayfix_customstats;
1766 // void(float index, float type, .void field) SV_AddStat = #232;
1767 // Set up an auto-sent player stat.
1768 // Client's get thier own fields sent to them. Index may not be less than 32.
1769 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1770 // 1: string (4 stats carrying a total of 16 charactures)
1771 // 2: float (one stat, float converted to an integer for transportation)
1772 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1773 static void VM_SV_AddStat(prvm_prog_t *prog)
1777 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1779 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1780 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1781 off = PRVM_G_INT (OFS_PARM2);
1790 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);
1796 VM_Warning(prog, "PF_SV_AddStat: index (%i) may not be less than %i\n", i, MIN_VM_STAT);
1800 if (i >= MAX_CL_STATS)
1802 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);
1806 if (i > (MAX_CL_STATS - 4) && type == 1)
1808 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);
1812 // these are hazardous to override but sort of allowed if one wants to be adventurous... and enjoys warnings.
1813 if (i < MIN_VM_STAT)
1814 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);
1815 else if (i >= MAX_VM_STAT && !sv_gameplayfix_customstats.integer)
1816 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);
1817 else if (i > (MAX_VM_STAT - 4) && type == 1 && !sv_gameplayfix_customstats.integer)
1818 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);
1820 vm_customstats[i].type = type;
1821 vm_customstats[i].fieldoffset = off;
1822 if(vm_customstats_last < i)
1823 vm_customstats_last = i;
1830 copies data from one entity to another
1832 copyentity(src, dst)
1835 static void VM_SV_copyentity(prvm_prog_t *prog)
1837 prvm_edict_t *in, *out;
1838 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1839 in = PRVM_G_EDICT(OFS_PARM0);
1840 if (in == prog->edicts)
1842 VM_Warning(prog, "copyentity: can not read world entity\n");
1847 VM_Warning(prog, "copyentity: can not read free entity\n");
1850 out = PRVM_G_EDICT(OFS_PARM1);
1851 if (out == prog->edicts)
1853 VM_Warning(prog, "copyentity: can not modify world entity\n");
1858 VM_Warning(prog, "copyentity: can not modify free entity\n");
1861 memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
1871 sets the color of a client and broadcasts the update to all connected clients
1873 setcolor(clientent, value)
1876 static void VM_SV_setcolor(prvm_prog_t *prog)
1881 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1882 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1883 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1885 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1887 Con_Print("tried to setcolor a non-client\n");
1891 client = svs.clients + entnum-1;
1894 PRVM_serveredictfloat(client->edict, clientcolors) = i;
1895 PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
1898 if (client->old_colors != client->colors)
1900 client->old_colors = client->colors;
1901 // send notification to all clients
1902 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1903 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1904 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1912 effect(origin, modelname, startframe, framecount, framerate)
1915 static void VM_SV_effect(prvm_prog_t *prog)
1920 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1921 s = PRVM_G_STRING(OFS_PARM1);
1924 VM_Warning(prog, "effect: no model specified\n");
1928 i = SV_ModelIndex(s, 1);
1931 VM_Warning(prog, "effect: model not precached\n");
1935 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1937 VM_Warning(prog, "effect: framecount < 1\n");
1941 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1943 VM_Warning(prog, "effect: framerate < 1\n");
1947 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1948 SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1951 static void VM_SV_te_blood(prvm_prog_t *prog)
1953 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1954 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1956 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1957 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1959 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1960 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1961 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1963 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1964 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1965 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1967 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1968 SV_FlushBroadcastMessages();
1971 static void VM_SV_te_bloodshower(prvm_prog_t *prog)
1973 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1974 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1976 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1977 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1979 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1980 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1981 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1983 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1984 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1985 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1987 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1989 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1990 SV_FlushBroadcastMessages();
1993 static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
1995 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1996 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1997 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1999 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2000 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2003 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
2004 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
2005 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
2006 SV_FlushBroadcastMessages();
2009 static void VM_SV_te_particlecube(prvm_prog_t *prog)
2011 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
2012 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2014 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2015 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2017 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2018 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2019 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2021 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2022 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2023 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2025 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2026 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2027 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2029 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2031 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2032 // gravity true/false
2033 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
2035 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
2036 SV_FlushBroadcastMessages();
2039 static void VM_SV_te_particlerain(prvm_prog_t *prog)
2041 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
2042 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2044 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2045 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2047 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2048 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2049 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2051 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2052 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2053 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2055 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2056 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2057 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2059 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2061 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2062 SV_FlushBroadcastMessages();
2065 static void VM_SV_te_particlesnow(prvm_prog_t *prog)
2067 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
2068 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2070 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2071 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2073 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2074 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2075 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2077 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2078 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2079 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2081 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2082 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2083 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2085 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2087 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2088 SV_FlushBroadcastMessages();
2091 static void VM_SV_te_spark(prvm_prog_t *prog)
2093 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
2094 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2096 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2097 MSG_WriteByte(&sv.datagram, TE_SPARK);
2099 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2100 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2101 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2103 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2104 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2105 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2107 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2108 SV_FlushBroadcastMessages();
2111 static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
2113 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
2114 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2115 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2117 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2118 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2119 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2120 SV_FlushBroadcastMessages();
2123 static void VM_SV_te_spikequad(prvm_prog_t *prog)
2125 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2126 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2127 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2129 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2130 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2131 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2132 SV_FlushBroadcastMessages();
2135 static void VM_SV_te_superspikequad(prvm_prog_t *prog)
2137 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2138 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2139 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2141 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2142 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2143 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2144 SV_FlushBroadcastMessages();
2147 static void VM_SV_te_explosionquad(prvm_prog_t *prog)
2149 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2150 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2151 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2153 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2154 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2155 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2156 SV_FlushBroadcastMessages();
2159 static void VM_SV_te_smallflash(prvm_prog_t *prog)
2161 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2162 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2163 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2165 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2166 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2167 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2168 SV_FlushBroadcastMessages();
2171 static void VM_SV_te_customflash(prvm_prog_t *prog)
2173 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2174 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2176 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2177 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2179 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2180 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2181 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2183 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2185 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2187 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2188 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2189 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2190 SV_FlushBroadcastMessages();
2193 static void VM_SV_te_gunshot(prvm_prog_t *prog)
2195 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2196 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2197 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2199 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2200 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2201 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2202 SV_FlushBroadcastMessages();
2205 static void VM_SV_te_spike(prvm_prog_t *prog)
2207 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2208 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2209 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2211 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2212 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2213 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2214 SV_FlushBroadcastMessages();
2217 static void VM_SV_te_superspike(prvm_prog_t *prog)
2219 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2220 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2221 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2223 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2224 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2225 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2226 SV_FlushBroadcastMessages();
2229 static void VM_SV_te_explosion(prvm_prog_t *prog)
2231 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2232 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2233 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2235 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2236 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2237 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2238 SV_FlushBroadcastMessages();
2241 static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
2243 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2244 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2245 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2247 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2248 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2249 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2250 SV_FlushBroadcastMessages();
2253 static void VM_SV_te_wizspike(prvm_prog_t *prog)
2255 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2256 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2257 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2259 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2260 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2261 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2262 SV_FlushBroadcastMessages();
2265 static void VM_SV_te_knightspike(prvm_prog_t *prog)
2267 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2268 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2269 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2271 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2272 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2273 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2274 SV_FlushBroadcastMessages();
2277 static void VM_SV_te_lavasplash(prvm_prog_t *prog)
2279 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2280 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2281 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2283 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2284 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2285 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2286 SV_FlushBroadcastMessages();
2289 static void VM_SV_te_teleport(prvm_prog_t *prog)
2291 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2292 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2293 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2295 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2296 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2297 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2298 SV_FlushBroadcastMessages();
2301 static void VM_SV_te_explosion2(prvm_prog_t *prog)
2303 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2304 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2305 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2307 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2309 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2311 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2312 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2313 SV_FlushBroadcastMessages();
2316 static void VM_SV_te_lightning1(prvm_prog_t *prog)
2318 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2319 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2320 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2322 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2324 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2325 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2326 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2331 SV_FlushBroadcastMessages();
2334 static void VM_SV_te_lightning2(prvm_prog_t *prog)
2336 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2337 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2338 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2340 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2342 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2343 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2344 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2346 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2347 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2348 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2349 SV_FlushBroadcastMessages();
2352 static void VM_SV_te_lightning3(prvm_prog_t *prog)
2354 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2355 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2356 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2358 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2360 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2361 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2362 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2364 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2365 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2366 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2367 SV_FlushBroadcastMessages();
2370 static void VM_SV_te_beam(prvm_prog_t *prog)
2372 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2373 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2374 MSG_WriteByte(&sv.datagram, TE_BEAM);
2376 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2378 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2382 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2383 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2384 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2385 SV_FlushBroadcastMessages();
2388 static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
2390 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2391 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2393 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2394 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2395 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2396 SV_FlushBroadcastMessages();
2399 static void VM_SV_te_flamejet(prvm_prog_t *prog)
2401 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2402 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2403 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2405 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2406 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2407 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2409 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2410 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2411 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2413 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2414 SV_FlushBroadcastMessages();
2417 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2418 //this function originally written by KrimZon, made shorter by LadyHavoc
2419 static void VM_SV_clientcommand(prvm_prog_t *prog)
2421 client_t *temp_client;
2423 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2425 //find client for this entity
2426 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2427 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2429 Con_Print("PF_clientcommand: entity is not a client\n");
2433 temp_client = host_client;
2434 host_client = svs.clients + i;
2435 Cmd_ExecuteString(cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
2436 host_client = temp_client;
2439 //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)
2440 static void VM_SV_setattachment(prvm_prog_t *prog)
2442 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2443 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2444 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2447 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2449 if (e == prog->edicts)
2451 VM_Warning(prog, "setattachment: can not modify world entity\n");
2456 VM_Warning(prog, "setattachment: can not modify free entity\n");
2460 if (tagentity == NULL)
2461 tagentity = prog->edicts;
2465 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2467 model = SV_GetModelFromEdict(tagentity);
2470 tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
2472 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);
2475 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));
2478 PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
2479 PRVM_serveredictfloat(e, tag_index) = tagindex;
2482 /////////////////////////////////////////
2483 // DP_MD3_TAGINFO extension coded by VorteX
2485 static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
2489 i = (int)PRVM_serveredictfloat(e, modelindex);
2490 if (i < 1 || i >= MAX_MODELS)
2493 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
2496 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2503 Matrix4x4_CreateIdentity(tag_localmatrix);
2505 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2507 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2518 void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix)
2521 float pitchsign = 1;
2523 scale = PRVM_serveredictfloat(ent, scale);
2528 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);
2531 pitchsign = SV_GetPitchSign(prog, ent);
2532 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);
2536 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2539 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2541 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2542 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2543 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2544 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2546 *out = identitymatrix;
2550 // Warnings/errors code:
2551 // 0 - normal (everything all-right)
2554 // 3 - null or non-precached model
2555 // 4 - no tags with requested index
2556 // 5 - runaway loop at attachment chain
2557 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2560 int modelindex, attachloop;
2561 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2564 *out = identitymatrix; // warnings and errors return identical matrix
2566 if (ent == prog->edicts)
2571 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
2572 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2575 model = SV_GetModelByIndex(modelindex);
2577 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2578 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2579 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2581 tagmatrix = identitymatrix;
2582 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2586 if (attachloop >= 256) // prevent runaway looping
2588 // apply transformation by child's tagindex on parent entity and then
2589 // by parent entity itself
2590 ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
2591 if (ret && attachloop == 0)
2593 SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
2594 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2595 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2596 // next iteration we process the parent entity
2597 if (PRVM_serveredictedict(ent, tag_entity))
2599 tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
2600 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
2607 // RENDER_VIEWMODEL magic
2608 if (PRVM_serveredictedict(ent, viewmodelforclient))
2610 Matrix4x4_Copy(&tagmatrix, out);
2611 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
2613 SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
2614 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2619 //float(entity ent, string tagname) gettagindex;
2621 static void VM_SV_gettagindex(prvm_prog_t *prog)
2624 const char *tag_name;
2627 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2629 ent = PRVM_G_EDICT(OFS_PARM0);
2630 tag_name = PRVM_G_STRING(OFS_PARM1);
2632 if (ent == prog->edicts)
2634 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2639 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2644 if (!SV_GetModelFromEdict(ent))
2645 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2648 tag_index = SV_GetTagIndex(prog, ent, tag_name);
2650 if(developer_extra.integer)
2651 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2653 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2656 //vector(entity ent, float tagindex) gettaginfo;
2657 static void VM_SV_gettaginfo(prvm_prog_t *prog)
2661 matrix4x4_t tag_matrix;
2662 matrix4x4_t tag_localmatrix;
2664 const char *tagname;
2666 vec3_t forward, left, up, origin;
2667 const model_t *model;
2669 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2671 e = PRVM_G_EDICT(OFS_PARM0);
2672 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2674 returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
2675 Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
2676 VectorCopy(forward, PRVM_serverglobalvector(v_forward));
2677 VectorNegate(left, PRVM_serverglobalvector(v_right));
2678 VectorCopy(up, PRVM_serverglobalvector(v_up));
2679 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
2680 model = SV_GetModelFromEdict(e);
2681 VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
2682 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
2683 VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
2684 SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2685 Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
2687 PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
2688 PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
2689 VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
2690 VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
2691 VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
2692 VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
2697 VM_Warning(prog, "gettagindex: can't affect world entity\n");
2700 VM_Warning(prog, "gettagindex: can't affect free entity\n");
2703 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2706 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2709 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2714 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2715 static void VM_SV_dropclient(prvm_prog_t *prog)
2718 client_t *oldhostclient;
2719 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2720 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2721 if (clientnum < 0 || clientnum >= svs.maxclients)
2723 VM_Warning(prog, "dropclient: not a client\n");
2726 if (!svs.clients[clientnum].active)
2728 VM_Warning(prog, "dropclient: that client slot is not connected\n");
2731 oldhostclient = host_client;
2732 host_client = svs.clients + clientnum;
2733 SV_DropClient(false, "Client dropped");
2734 host_client = oldhostclient;
2737 //entity() spawnclient (DP_SV_BOTCLIENT)
2738 static void VM_SV_spawnclient(prvm_prog_t *prog)
2742 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2743 prog->xfunction->builtinsprofile += 2;
2745 for (i = 0;i < svs.maxclients;i++)
2747 if (!svs.clients[i].active)
2749 prog->xfunction->builtinsprofile += 100;
2750 SV_ConnectClient (i, NULL);
2751 // this has to be set or else ClientDisconnect won't be called
2752 // we assume the qc will call ClientConnect...
2753 svs.clients[i].clientconnectcalled = true;
2754 ed = PRVM_EDICT_NUM(i + 1);
2758 VM_RETURN_EDICT(ed);
2761 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2762 static void VM_SV_clienttype(prvm_prog_t *prog)
2765 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2766 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2767 if (clientnum < 0 || clientnum >= svs.maxclients)
2768 PRVM_G_FLOAT(OFS_RETURN) = 3; // CLIENTTYPE_NOTACLIENT
2769 else if (!svs.clients[clientnum].active)
2770 PRVM_G_FLOAT(OFS_RETURN) = 0; // CLIENTTYPE_DISCONNECTED
2771 else if (svs.clients[clientnum].netconnection)
2772 PRVM_G_FLOAT(OFS_RETURN) = 1; // CLIENTTYPE_REAL
2774 PRVM_G_FLOAT(OFS_RETURN) = 2; // CLIENTTYPE_BOT
2781 string(string key) serverkey
2784 static void VM_SV_serverkey(prvm_prog_t *prog)
2786 char string[VM_STRINGTEMP_LENGTH];
2787 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2788 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2789 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2792 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2793 static void VM_SV_setmodelindex(prvm_prog_t *prog)
2798 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2800 e = PRVM_G_EDICT(OFS_PARM0);
2801 if (e == prog->edicts)
2803 VM_Warning(prog, "setmodelindex: can not modify world entity\n");
2808 VM_Warning(prog, "setmodelindex: can not modify free entity\n");
2811 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2812 if (i <= 0 || i >= MAX_MODELS)
2814 VM_Warning(prog, "setmodelindex: invalid modelindex\n");
2817 if (!sv.model_precache[i][0])
2819 VM_Warning(prog, "setmodelindex: model not precached\n");
2823 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2824 PRVM_serveredictfloat(e, modelindex) = i;
2826 mod = SV_GetModelByIndex(i);
2830 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2831 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
2833 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
2836 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
2839 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2840 static void VM_SV_modelnameforindex(prvm_prog_t *prog)
2843 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2845 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2847 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2848 if (i <= 0 || i >= MAX_MODELS)
2850 VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
2853 if (!sv.model_precache[i][0])
2855 VM_Warning(prog, "modelnameforindex: model not precached\n");
2859 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2862 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2863 static void VM_SV_particleeffectnum(prvm_prog_t *prog)
2866 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2867 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2870 PRVM_G_FLOAT(OFS_RETURN) = i;
2873 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2874 static void VM_SV_trailparticles(prvm_prog_t *prog)
2877 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2879 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2882 MSG_WriteByte(&sv.datagram, svc_trailparticles);
2883 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2884 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2885 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2886 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2887 MSG_WriteVector(&sv.datagram, start, sv.protocol);
2888 MSG_WriteVector(&sv.datagram, end, sv.protocol);
2889 SV_FlushBroadcastMessages();
2892 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
2893 static void VM_SV_pointparticles(prvm_prog_t *prog)
2895 int effectnum, count;
2897 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
2899 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2902 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2903 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
2904 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2905 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
2906 if (count == 1 && !VectorLength2(vel))
2909 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
2910 MSG_WriteShort(&sv.datagram, effectnum);
2911 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2915 // 1+2+12+12+2=29 bytes
2916 MSG_WriteByte(&sv.datagram, svc_pointparticles);
2917 MSG_WriteShort(&sv.datagram, effectnum);
2918 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2919 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
2920 MSG_WriteShort(&sv.datagram, count);
2923 SV_FlushBroadcastMessages();
2926 qbool SV_VM_ConsoleCommand (const char *text)
2928 prvm_prog_t *prog = SVVM_prog;
2929 return PRVM_ConsoleCommand(prog, text, &prog->funcoffsets.ConsoleCmd, true, PRVM_EDICT_TO_PROG(sv.world.prog->edicts), sv.time, !(!sv.active || !prog || !prog->loaded), "QC function ConsoleCmd is missing");
2932 // #352 void(string cmdname) registercommand (EXT_CSQC)
2933 static void VM_SV_registercommand (prvm_prog_t *prog)
2935 VM_SAFEPARMCOUNT(1, VM_SV_registercmd);
2936 Cmd_AddCommand(CF_SERVER, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
2939 //PF_setpause, // void(float pause) setpause = #531;
2940 static void VM_SV_setpause(prvm_prog_t *prog) {
2942 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
2943 if (pauseValue != 0) { //pause the game
2945 sv.pausedstart = host.realtime;
2946 } else { //disable pause, in case it was enabled
2947 if (sv.paused != 0) {
2952 // send notification to all clients
2953 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
2954 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
2957 // #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.
2958 static void VM_SV_skel_create(prvm_prog_t *prog)
2960 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
2961 model_t *model = SV_GetModelByIndex(modelindex);
2962 skeleton_t *skeleton;
2964 PRVM_G_FLOAT(OFS_RETURN) = 0;
2965 if (!model || !model->num_bones)
2967 for (i = 0;i < MAX_EDICTS;i++)
2968 if (!prog->skeletons[i])
2970 if (i == MAX_EDICTS)
2972 prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
2973 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
2974 skeleton->model = model;
2975 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
2976 // initialize to identity matrices
2977 for (i = 0;i < skeleton->model->num_bones;i++)
2978 skeleton->relativetransforms[i] = identitymatrix;
2981 // #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
2982 static void VM_SV_skel_build(prvm_prog_t *prog)
2984 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2985 skeleton_t *skeleton;
2986 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
2987 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
2988 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
2989 int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
2990 int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
2991 model_t *model = SV_GetModelByIndex(modelindex);
2995 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
2996 frameblend_t frameblend[MAX_FRAMEBLENDS];
2997 matrix4x4_t bonematrix;
2999 PRVM_G_FLOAT(OFS_RETURN) = 0;
3000 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3002 firstbone = max(0, firstbone);
3003 lastbone = min(lastbone, model->num_bones - 1);
3004 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3005 VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
3006 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
3007 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3009 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3011 memset(&bonematrix, 0, sizeof(bonematrix));
3012 for (blendindex = 0;blendindex < numblends;blendindex++)
3014 Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3015 Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
3017 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
3018 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
3020 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
3023 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3024 static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
3026 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3027 skeleton_t *skeleton;
3028 PRVM_G_FLOAT(OFS_RETURN) = 0;
3029 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3031 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3034 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3035 static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
3037 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3038 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3039 skeleton_t *skeleton;
3040 PRVM_G_INT(OFS_RETURN) = 0;
3041 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3043 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3045 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
3048 // #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)
3049 static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
3051 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3052 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3053 skeleton_t *skeleton;
3054 PRVM_G_FLOAT(OFS_RETURN) = 0;
3055 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3057 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3059 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3062 // #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
3063 static void VM_SV_skel_find_bone(prvm_prog_t *prog)
3065 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3066 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3067 skeleton_t *skeleton;
3068 PRVM_G_FLOAT(OFS_RETURN) = 0;
3069 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3071 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3074 // #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)
3075 static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
3077 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3078 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3079 skeleton_t *skeleton;
3081 vec3_t forward, left, up, origin;
3082 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3083 VectorClear(PRVM_clientglobalvector(v_forward));
3084 VectorClear(PRVM_clientglobalvector(v_right));
3085 VectorClear(PRVM_clientglobalvector(v_up));
3086 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3088 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3090 matrix = skeleton->relativetransforms[bonenum];
3091 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3092 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3093 VectorNegate(left, PRVM_clientglobalvector(v_right));
3094 VectorCopy(up, PRVM_clientglobalvector(v_up));
3095 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3098 // #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)
3099 static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
3101 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3102 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3103 skeleton_t *skeleton;
3106 vec3_t forward, left, up, origin;
3107 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3108 VectorClear(PRVM_clientglobalvector(v_forward));
3109 VectorClear(PRVM_clientglobalvector(v_right));
3110 VectorClear(PRVM_clientglobalvector(v_up));
3111 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3113 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3115 matrix = skeleton->relativetransforms[bonenum];
3116 // convert to absolute
3117 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3120 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3122 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3123 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3124 VectorNegate(left, PRVM_clientglobalvector(v_right));
3125 VectorCopy(up, PRVM_clientglobalvector(v_up));
3126 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3129 // #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)
3130 static void VM_SV_skel_set_bone(prvm_prog_t *prog)
3132 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3133 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3134 vec3_t forward, left, up, origin;
3135 skeleton_t *skeleton;
3137 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3139 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3141 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3142 VectorNegate(PRVM_clientglobalvector(v_right), left);
3143 VectorCopy(PRVM_clientglobalvector(v_up), up);
3144 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3145 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3146 skeleton->relativetransforms[bonenum] = matrix;
3149 // #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)
3150 static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
3152 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3153 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3154 vec3_t forward, left, up, origin;
3155 skeleton_t *skeleton;
3158 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3160 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3162 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3163 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3164 VectorNegate(PRVM_clientglobalvector(v_right), left);
3165 VectorCopy(PRVM_clientglobalvector(v_up), up);
3166 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3167 temp = skeleton->relativetransforms[bonenum];
3168 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3171 // #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)
3172 static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
3174 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3175 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3176 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3178 vec3_t forward, left, up, origin;
3179 skeleton_t *skeleton;
3182 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3184 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3185 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3186 VectorNegate(PRVM_clientglobalvector(v_right), left);
3187 VectorCopy(PRVM_clientglobalvector(v_up), up);
3188 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3189 firstbone = max(0, firstbone);
3190 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3191 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3193 temp = skeleton->relativetransforms[bonenum];
3194 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3198 // #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
3199 static void VM_SV_skel_copybones(prvm_prog_t *prog)
3201 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3202 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3203 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3204 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3206 skeleton_t *skeletondst;
3207 skeleton_t *skeletonsrc;
3208 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3210 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3212 firstbone = max(0, firstbone);
3213 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3214 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3215 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3216 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3219 // #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)
3220 static void VM_SV_skel_delete(prvm_prog_t *prog)
3222 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3223 skeleton_t *skeleton;
3224 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3227 prog->skeletons[skeletonindex] = NULL;
3230 // #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
3231 static void VM_SV_frameforname(prvm_prog_t *prog)
3233 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3234 model_t *model = SV_GetModelByIndex(modelindex);
3235 const char *name = PRVM_G_STRING(OFS_PARM1);
3237 PRVM_G_FLOAT(OFS_RETURN) = -1;
3238 if (!model || !model->animscenes)
3240 for (i = 0;i < model->numframes;i++)
3242 if (!strcasecmp(model->animscenes[i].name, name))
3244 PRVM_G_FLOAT(OFS_RETURN) = i;
3250 // #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.
3251 static void VM_SV_frameduration(prvm_prog_t *prog)
3253 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3254 model_t *model = SV_GetModelByIndex(modelindex);
3255 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3256 PRVM_G_FLOAT(OFS_RETURN) = 0;
3257 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3259 if (model->animscenes[framenum].framerate)
3260 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3264 prvm_builtin_t vm_sv_builtins[] = {
3265 NULL, // #0 NULL function (not callable) (QUAKE)
3266 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3267 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3268 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3269 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3270 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3271 VM_break, // #6 void() break (QUAKE)
3272 VM_random, // #7 float() random (QUAKE)
3273 VM_SV_sound, // #8 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
3274 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3275 VM_error, // #10 void(string e) error (QUAKE)
3276 VM_objerror, // #11 void(string e) objerror (QUAKE)
3277 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3278 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3279 VM_spawn, // #14 entity() spawn (QUAKE)
3280 VM_remove, // #15 void(entity e) remove (QUAKE)
3281 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3282 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3283 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3284 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3285 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3286 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3287 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3288 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3289 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3290 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3291 VM_ftos, // #26 string(float f) ftos (QUAKE)
3292 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3293 VM_coredump, // #28 void() coredump (QUAKE)
3294 VM_traceon, // #29 void() traceon (QUAKE)
3295 VM_traceoff, // #30 void() traceoff (QUAKE)
3296 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3297 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3298 NULL, // #33 (QUAKE)
3299 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3300 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3301 VM_rint, // #36 float(float v) rint (QUAKE)
3302 VM_floor, // #37 float(float v) floor (QUAKE)
3303 VM_ceil, // #38 float(float v) ceil (QUAKE)
3304 NULL, // #39 (QUAKE)
3305 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3306 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3307 NULL, // #42 (QUAKE)
3308 VM_fabs, // #43 float(float f) fabs (QUAKE)
3309 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3310 VM_cvar, // #45 float(string s) cvar (QUAKE)
3311 VM_localcmd_server, // #46 void(string s) localcmd (QUAKE)
3312 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3313 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3314 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3315 NULL, // #50 (QUAKE)
3316 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3317 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3318 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3319 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3320 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3321 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3322 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3323 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3324 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3325 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3326 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3327 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3328 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3329 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3330 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3331 NULL, // #66 (QUAKE)
3332 VM_SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3333 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3334 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3335 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3336 NULL, // #71 (QUAKE)
3337 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3338 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3339 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3340 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3341 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3342 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3343 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3344 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3345 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3346 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3347 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3348 NULL, // #83 (QUAKE)
3349 NULL, // #84 (QUAKE)
3350 NULL, // #85 (QUAKE)
3351 NULL, // #86 (QUAKE)
3352 NULL, // #87 (QUAKE)
3353 NULL, // #88 (QUAKE)
3354 NULL, // #89 (QUAKE)
3355 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3356 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3357 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3358 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3359 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3360 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3361 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3362 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3363 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3364 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3365 // FrikaC and Telejano range #100-#199
3376 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3377 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3378 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3379 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3380 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3381 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3382 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3383 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3384 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3385 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3466 // FTEQW range #200-#299
3485 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3488 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3489 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3490 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3491 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3492 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3493 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3494 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3495 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3496 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3497 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3499 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3507 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3530 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.
3531 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
3532 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3533 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3534 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)
3535 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
3536 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)
3537 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)
3538 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)
3539 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)
3540 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)
3541 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
3542 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)
3543 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
3544 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.
3567 // CSQC range #300-#399
3568 NULL, // #300 void() clearscene (EXT_CSQC)
3569 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3570 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3571 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3572 NULL, // #304 void() renderscene (EXT_CSQC)
3573 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3574 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3575 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3576 NULL, // #308 void() R_EndPolygon
3578 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3579 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3583 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3584 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3585 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3586 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3587 NULL, // #319 void(string name) freepic (EXT_CSQC)
3588 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3589 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3590 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3591 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3592 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3593 NULL, // #325 void(void) drawresetcliparea
3598 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3599 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3600 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3601 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3602 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3603 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3604 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3605 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3606 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3607 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3608 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3609 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3610 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3611 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3612 NULL, // #344 vector() getmousepos (EXT_CSQC)
3613 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3614 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3615 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3616 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3617 NULL, // #349 float() isdemo (EXT_CSQC)
3618 VM_isserver, // #350 float() isserver (EXT_CSQC)
3619 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3620 VM_SV_registercommand, // #352 void(string cmdname) registercommand (EXT_CSQC)
3621 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3622 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3628 NULL, // #360 float() readbyte (EXT_CSQC)
3629 NULL, // #361 float() readchar (EXT_CSQC)
3630 NULL, // #362 float() readshort (EXT_CSQC)
3631 NULL, // #363 float() readlong (EXT_CSQC)
3632 NULL, // #364 float() readcoord (EXT_CSQC)
3633 NULL, // #365 float() readangle (EXT_CSQC)
3634 NULL, // #366 string() readstring (EXT_CSQC)
3635 NULL, // #367 float() readfloat (EXT_CSQC)
3668 // LadyHavoc's range #400-#499
3669 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3670 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3671 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3672 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3673 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3674 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3675 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3676 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3677 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)
3678 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3679 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3680 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3681 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3682 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3683 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3684 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3685 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3686 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3687 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3688 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3689 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3690 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3691 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3692 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3693 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3694 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3695 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3696 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3697 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3698 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3699 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3700 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3701 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3702 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3703 VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3704 VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3705 VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3706 VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3707 VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3708 VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3709 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3710 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3711 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3712 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3713 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3714 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3715 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3716 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3717 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3718 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3719 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3720 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3721 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3722 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3723 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3724 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3725 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3726 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3728 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3729 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3730 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3731 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3732 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3733 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3734 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3735 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3736 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3737 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3738 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3740 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3741 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3742 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3743 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3744 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3745 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3746 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3747 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3748 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3749 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3750 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3751 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3752 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3753 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3754 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3755 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3763 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3764 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3765 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3766 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3767 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3768 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3769 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3770 VM_SV_WritePicture, // #501
3772 VM_whichpack, // #503 string(string) whichpack = #503;
3779 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3780 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3781 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3782 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)
3783 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3784 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3785 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3786 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3787 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3788 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3798 VM_loadfromdata, // #529
3799 VM_loadfromfile, // #530
3800 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3802 VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
3803 VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
3804 VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
3805 VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
3806 VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
3807 VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
3809 VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
3810 VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
3811 VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
3835 VM_SV_findbox, // #566 entity(vector mins, vector maxs) findbox = #566; (DP_QC_FINDBOX)
3874 VM_callfunction, // #605
3875 VM_writetofile, // #606
3876 VM_isfunction, // #607
3882 VM_parseentitydata, // #613
3893 VM_SV_getextresponse, // #624 string getextresponse(void)
3896 VM_sprintf, // #627 string sprintf(string format, ...)
3897 VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
3898 VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
3908 VM_digest_hex, // #639
3911 VM_coverage, // #642
3915 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
3917 void SVVM_init_cmd(prvm_prog_t *prog)
3922 void SVVM_reset_cmd(prvm_prog_t *prog)
3924 World_End(&sv.world);
3926 if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
3928 func_t s = PRVM_serverfunction(SV_Shutdown);
3929 PRVM_serverglobalfloat(time) = sv.time;
3930 PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
3931 prog->ExecuteProgram(prog, s,"SV_Shutdown() required");