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",
233 //"EXT_CSQC" // not ready yet
240 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.
242 setorigin (entity, origin)
245 static void VM_SV_setorigin(prvm_prog_t *prog)
249 VM_SAFEPARMCOUNT(2, VM_SV_setorigin);
251 e = PRVM_G_EDICT(OFS_PARM0);
252 if (e == prog->edicts)
254 VM_Warning(prog, "setorigin: can not modify world entity\n");
257 if (e->priv.server->free)
259 VM_Warning(prog, "setorigin: can not modify free entity\n");
262 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), PRVM_serveredictvector(e, origin));
263 if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
264 e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
268 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
269 static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max, qbool rotate)
273 for (i=0 ; i<3 ; i++)
275 prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
277 // set derived values
278 VectorCopy (min, PRVM_serveredictvector(e, mins));
279 VectorCopy (max, PRVM_serveredictvector(e, maxs));
280 VectorSubtract (max, min, PRVM_serveredictvector(e, size));
289 the size box is rotated by the current angle
290 LadyHavoc: no it isn't...
292 setsize (entity, minvector, maxvector)
295 static void VM_SV_setsize(prvm_prog_t *prog)
300 VM_SAFEPARMCOUNT(3, VM_SV_setsize);
302 e = PRVM_G_EDICT(OFS_PARM0);
303 if (e == prog->edicts)
305 VM_Warning(prog, "setsize: can not modify world entity\n");
308 if (e->priv.server->free)
310 VM_Warning(prog, "setsize: can not modify free entity\n");
313 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
314 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
315 SetMinMaxSize(prog, e, mins, maxs, false);
323 setmodel(entity, model)
326 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
327 static void VM_SV_setmodel(prvm_prog_t *prog)
333 VM_SAFEPARMCOUNT(2, VM_SV_setmodel);
335 e = PRVM_G_EDICT(OFS_PARM0);
336 if (e == prog->edicts)
338 VM_Warning(prog, "setmodel: can not modify world entity\n");
341 if (e->priv.server->free)
343 VM_Warning(prog, "setmodel: can not modify free entity\n");
346 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
347 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
348 PRVM_serveredictfloat(e, modelindex) = i;
350 mod = SV_GetModelByIndex(i);
354 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
355 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
357 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
360 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
367 single print to a specific client
369 sprint(clientent, value)
372 static void VM_SV_sprint(prvm_prog_t *prog)
376 char string[VM_STRINGTEMP_LENGTH];
378 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
380 VM_VarString(prog, 1, string, sizeof(string));
382 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
383 // LadyHavoc: div0 requested that sprintto world operate like print
390 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
392 VM_Warning(prog, "tried to centerprint to a non-client\n");
396 client = svs.clients + entnum-1;
397 if (!client->netconnection)
400 MSG_WriteChar(&client->netconnection->message,svc_print);
401 MSG_WriteString(&client->netconnection->message, string);
409 single print to a specific client
411 centerprint(clientent, value)
414 static void VM_SV_centerprint(prvm_prog_t *prog)
418 char string[VM_STRINGTEMP_LENGTH];
420 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
422 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
424 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
426 VM_Warning(prog, "tried to centerprint to a non-client\n");
430 client = svs.clients + entnum-1;
431 if (!client->netconnection)
434 VM_VarString(prog, 1, string, sizeof(string));
435 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
436 MSG_WriteString(&client->netconnection->message, string);
443 particle(origin, color, count)
446 static void VM_SV_particle(prvm_prog_t *prog)
452 VM_SAFEPARMCOUNT(4, VM_SV_particle);
454 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
455 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
456 color = (int)PRVM_G_FLOAT(OFS_PARM2);
457 count = (int)PRVM_G_FLOAT(OFS_PARM3);
458 SV_StartParticle (org, dir, color, count);
468 static void VM_SV_ambientsound(prvm_prog_t *prog)
472 prvm_vec_t vol, attenuation;
475 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
477 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
478 samp = PRVM_G_STRING(OFS_PARM1);
479 vol = PRVM_G_FLOAT(OFS_PARM2);
480 attenuation = PRVM_G_FLOAT(OFS_PARM3);
482 // check to see if samp was properly precached
483 soundnum = SV_SoundIndex(samp, 1);
491 // add an svc_spawnambient command to the level signon packet
494 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
496 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
498 MSG_WriteVector(&sv.signon, pos, sv.protocol);
500 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
501 MSG_WriteShort (&sv.signon, soundnum);
503 MSG_WriteByte (&sv.signon, soundnum);
505 MSG_WriteByte (&sv.signon, (int)(vol*255));
506 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
514 Each entity can have eight independant sound sources, like voice,
517 Channel 0 is an auto-allocate channel, the others override anything
518 already running on that entity/channel pair.
520 An attenuation of 0 will play full volume everywhere in the level.
521 Larger attenuations will drop off.
523 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
526 static void VM_SV_sound(prvm_prog_t *prog)
530 prvm_edict_t *entity;
536 VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
538 entity = PRVM_G_EDICT(OFS_PARM0);
539 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
540 sample = PRVM_G_STRING(OFS_PARM2);
541 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
544 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
548 attenuation = PRVM_G_FLOAT(OFS_PARM4);
552 pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
557 if(channel >= 8 && channel <= 15) // weird QW feature
559 flags |= CHANNELFLAG_RELIABLE;
565 // LadyHavoc: we only let the qc set certain flags, others are off-limits
566 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
569 if (nvolume < 0 || nvolume > 255)
571 VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
575 if (attenuation < 0 || attenuation > 4)
577 VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
581 channel = CHAN_USER2ENGINE(channel);
583 if (!IS_CHAN(channel))
585 VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
589 SV_StartSound (entity, channel, sample, nvolume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange);
596 Follows the same logic as VM_SV_sound, except instead of
597 an entity, an origin for the sound is provided, and channel
598 is omitted (since no entity is being tracked).
602 static void VM_SV_pointsound(prvm_prog_t *prog)
610 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
612 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
613 sample = PRVM_G_STRING(OFS_PARM1);
614 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
615 attenuation = PRVM_G_FLOAT(OFS_PARM3);
616 pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
618 if (nvolume < 0 || nvolume > 255)
620 VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
624 if (attenuation < 0 || attenuation > 4)
626 VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
630 SV_StartPointSound (org, sample, nvolume, attenuation, pitchchange);
637 Used for use tracing and shot targeting
638 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
639 if the tryents flag is set.
641 traceline (vector1, vector2, movetype, ignore)
644 static void VM_SV_traceline(prvm_prog_t *prog)
651 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
653 prog->xfunction->builtinsprofile += 30;
655 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
656 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
657 move = (int)PRVM_G_FLOAT(OFS_PARM2);
658 ent = PRVM_G_EDICT(OFS_PARM3);
660 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]))
661 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));
663 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value);
665 VM_SetTraceGlobals(prog, &trace);
673 Used for use tracing and shot targeting
674 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
675 if the tryents flag is set.
677 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
680 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
681 static void VM_SV_tracebox(prvm_prog_t *prog)
683 vec3_t v1, v2, m1, m2;
688 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
690 prog->xfunction->builtinsprofile += 30;
692 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
693 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
694 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
695 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
696 move = (int)PRVM_G_FLOAT(OFS_PARM4);
697 ent = PRVM_G_EDICT(OFS_PARM5);
699 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]))
700 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));
702 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value);
704 VM_SetTraceGlobals(prog, &trace);
707 static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
711 vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
712 vec3_t original_origin;
713 vec3_t original_velocity;
714 vec3_t original_angles;
715 vec3_t original_avelocity;
718 VectorCopy(PRVM_serveredictvector(tossent, origin) , original_origin );
719 VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
720 VectorCopy(PRVM_serveredictvector(tossent, angles) , original_angles );
721 VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
723 gravity = PRVM_serveredictfloat(tossent, gravity);
726 gravity *= sv_gravity.value * 0.025;
728 for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
730 SV_CheckVelocity (tossent);
731 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
732 VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
733 VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
734 VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
735 VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
736 VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
737 VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
738 trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value);
739 VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
740 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
742 if (trace.fraction < 1)
746 VectorCopy(original_origin , PRVM_serveredictvector(tossent, origin) );
747 VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
748 VectorCopy(original_angles , PRVM_serveredictvector(tossent, angles) );
749 VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
754 static void VM_SV_tracetoss(prvm_prog_t *prog)
758 prvm_edict_t *ignore;
760 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
762 prog->xfunction->builtinsprofile += 600;
764 ent = PRVM_G_EDICT(OFS_PARM0);
765 if (ent == prog->edicts)
767 VM_Warning(prog, "tracetoss: can not use world entity\n");
770 ignore = PRVM_G_EDICT(OFS_PARM1);
772 trace = SV_Trace_Toss(prog, ent, ignore);
774 VM_SetTraceGlobals(prog, &trace);
777 //============================================================================
779 static int checkpvsbytes;
780 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
782 static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
788 // cycle to the next one
790 check = bound(1, check, svs.maxclients);
791 if (check == svs.maxclients)
799 prog->xfunction->builtinsprofile++;
801 if (i == svs.maxclients+1)
803 // look up the client's edict
804 ent = PRVM_EDICT_NUM(i);
805 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
806 if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
808 // found a valid client (possibly the same one again)
812 // get the PVS for the entity
813 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
815 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
816 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
825 Returns a client (or object that has a client enemy) that would be a
828 If there is more than one valid option, they are cycled each frame
830 If (self.origin + self.viewofs) is not in the PVS of the current target,
831 it is not returned at all.
836 int c_invis, c_notvis;
837 static void VM_SV_checkclient(prvm_prog_t *prog)
839 prvm_edict_t *ent, *self;
842 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
844 // find a new check if on a new frame
845 if (sv.time - sv.lastchecktime >= 0.1)
847 sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
848 sv.lastchecktime = sv.time;
851 // return check if it might be visible
852 ent = PRVM_EDICT_NUM(sv.lastcheck);
853 if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
855 VM_RETURN_EDICT(prog->edicts);
859 // if current entity can't possibly see the check entity, return 0
860 self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
861 VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
862 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
865 VM_RETURN_EDICT(prog->edicts);
869 // might be able to see it
871 VM_RETURN_EDICT(ent);
874 //============================================================================
880 Checks if an entity is in a point's PVS.
881 Should be fast but can be inexact.
883 float checkpvs(vector viewpos, entity viewee) = #240;
886 static void VM_SV_checkpvs(prvm_prog_t *prog)
888 vec3_t viewpos, absmin, absmax;
889 prvm_edict_t *viewee;
894 unsigned char fatpvs[MAX_MAP_LEAFS/8];
897 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
898 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
899 viewee = PRVM_G_EDICT(OFS_PARM1);
901 if(viewee->priv.server->free)
903 VM_Warning(prog, "checkpvs: can not check free entity\n");
904 PRVM_G_FLOAT(OFS_RETURN) = 4;
909 if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
911 // no PVS support on this worldmodel... darn
912 PRVM_G_FLOAT(OFS_RETURN) = 3;
915 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
918 // viewpos isn't in any PVS... darn
919 PRVM_G_FLOAT(OFS_RETURN) = 2;
922 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
923 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
924 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
926 // using fat PVS like FTEQW does (slow)
927 if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
929 // no PVS support on this worldmodel... darn
930 PRVM_G_FLOAT(OFS_RETURN) = 3;
933 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
936 // viewpos isn't in any PVS... darn
937 PRVM_G_FLOAT(OFS_RETURN) = 2;
940 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
941 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
942 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
951 Sends text over to the client's execution buffer
953 stuffcmd (clientent, value, ...)
956 static void VM_SV_stuffcmd(prvm_prog_t *prog)
960 char string[VM_STRINGTEMP_LENGTH];
962 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
964 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
965 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
967 VM_Warning(prog, "Can't stuffcmd to a non-client\n");
971 VM_VarString(prog, 1, string, sizeof(string));
974 host_client = svs.clients + entnum-1;
975 SV_ClientCommands ("%s", string);
983 Returns a chain of entities that have origins within a spherical area
985 findradius (origin, radius)
988 static void VM_SV_findradius(prvm_prog_t *prog)
990 prvm_edict_t *ent, *chain;
991 vec_t radius, radius2;
992 vec3_t org, eorg, mins, maxs;
995 static prvm_edict_t *touchedicts[MAX_EDICTS];
998 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
1001 chainfield = PRVM_G_INT(OFS_PARM2);
1003 chainfield = prog->fieldoffsets.chain;
1005 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
1007 chain = (prvm_edict_t *)prog->edicts;
1009 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1010 radius = PRVM_G_FLOAT(OFS_PARM1);
1011 radius2 = radius * radius;
1013 mins[0] = org[0] - (radius + 1);
1014 mins[1] = org[1] - (radius + 1);
1015 mins[2] = org[2] - (radius + 1);
1016 maxs[0] = org[0] + (radius + 1);
1017 maxs[1] = org[1] + (radius + 1);
1018 maxs[2] = org[2] + (radius + 1);
1019 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1020 if (numtouchedicts > MAX_EDICTS)
1022 // this never happens
1023 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1024 numtouchedicts = MAX_EDICTS;
1026 for (i = 0;i < numtouchedicts;i++)
1028 ent = touchedicts[i];
1029 prog->xfunction->builtinsprofile++;
1030 // Quake did not return non-solid entities but darkplaces does
1031 // (note: this is the reason you can't blow up fallen zombies)
1032 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1034 // LadyHavoc: compare against bounding box rather than center so it
1035 // doesn't miss large objects, and use DotProduct instead of Length
1036 // for a major speedup
1037 VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
1038 if (sv_gameplayfix_findradiusdistancetobox.integer)
1040 eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
1041 eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
1042 eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
1045 VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
1046 if (DotProduct(eorg, eorg) < radius2)
1048 PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
1053 VM_RETURN_EDICT(chain);
1056 static void VM_SV_precache_sound(prvm_prog_t *prog)
1058 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1059 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1062 static void VM_SV_precache_model(prvm_prog_t *prog)
1064 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1065 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1066 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1073 float(float yaw, float dist[, settrace]) walkmove
1076 static void VM_SV_walkmove(prvm_prog_t *prog)
1085 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1087 // assume failure if it returns early
1088 PRVM_G_FLOAT(OFS_RETURN) = 0;
1090 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1091 if (ent == prog->edicts)
1093 VM_Warning(prog, "walkmove: can not modify world entity\n");
1096 if (ent->priv.server->free)
1098 VM_Warning(prog, "walkmove: can not modify free entity\n");
1101 yaw = PRVM_G_FLOAT(OFS_PARM0);
1102 dist = PRVM_G_FLOAT(OFS_PARM1);
1103 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1105 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1108 yaw = yaw*M_PI*2 / 360;
1110 move[0] = cos(yaw)*dist;
1111 move[1] = sin(yaw)*dist;
1114 // save program state, because SV_movestep may call other progs
1115 oldf = prog->xfunction;
1116 oldself = PRVM_serverglobaledict(self);
1118 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1121 // restore program state
1122 prog->xfunction = oldf;
1123 PRVM_serverglobaledict(self) = oldself;
1134 static void VM_SV_droptofloor(prvm_prog_t *prog)
1137 vec3_t end, entorigin, entmins, entmaxs;
1140 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1142 // assume failure if it returns early
1143 PRVM_G_FLOAT(OFS_RETURN) = 0;
1145 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1146 if (ent == prog->edicts)
1148 VM_Warning(prog, "droptofloor: can not modify world entity\n");
1151 if (ent->priv.server->free)
1153 VM_Warning(prog, "droptofloor: can not modify free entity\n");
1157 VectorCopy (PRVM_serveredictvector(ent, origin), end);
1160 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1161 SV_NudgeOutOfSolid(ent);
1163 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
1164 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
1165 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
1166 trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1167 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1170 VectorSet(offset, 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]), 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]), PRVM_serveredictvector(ent, mins)[2]);
1171 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
1172 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1173 VectorSubtract(trace.endpos, offset, trace.endpos);
1174 if (trace.startsolid)
1176 Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1178 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1179 PRVM_serveredictedict(ent, groundentity) = 0;
1180 PRVM_G_FLOAT(OFS_RETURN) = 1;
1182 else if (trace.fraction < 1)
1184 Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1185 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1186 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1187 SV_NudgeOutOfSolid(ent);
1189 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1190 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1191 PRVM_G_FLOAT(OFS_RETURN) = 1;
1192 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1193 ent->priv.server->suspendedinairflag = true;
1198 if (!trace.allsolid && trace.fraction < 1)
1200 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1202 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1203 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1204 PRVM_G_FLOAT(OFS_RETURN) = 1;
1205 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1206 ent->priv.server->suspendedinairflag = true;
1215 void(float style, string value) lightstyle
1218 static void VM_SV_lightstyle(prvm_prog_t *prog)
1225 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1227 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1228 val = PRVM_G_STRING(OFS_PARM1);
1230 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1231 prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
1234 // change the string in sv
1235 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1237 // send message to all clients on this server
1238 if (sv.state != ss_active)
1241 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1243 if (client->active && client->netconnection)
1245 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1246 MSG_WriteChar (&client->netconnection->message,style);
1247 MSG_WriteString (&client->netconnection->message, val);
1257 static void VM_SV_checkbottom(prvm_prog_t *prog)
1259 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1260 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1268 static void VM_SV_pointcontents(prvm_prog_t *prog)
1271 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1272 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
1273 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(point));
1280 Pick a vector for the player to shoot along
1281 vector aim(entity, missilespeed)
1284 static void VM_SV_aim(prvm_prog_t *prog)
1286 prvm_edict_t *ent, *check, *bestent;
1287 vec3_t start, dir, end, bestdir;
1290 float dist, bestdist;
1293 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1295 // assume failure if it returns early
1296 VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1297 // if sv_aim is so high it can't possibly accept anything, skip out early
1298 if (sv_aim.value >= 1)
1301 ent = PRVM_G_EDICT(OFS_PARM0);
1302 if (ent == prog->edicts)
1304 VM_Warning(prog, "aim: can not use world entity\n");
1307 if (ent->priv.server->free)
1309 VM_Warning(prog, "aim: can not use free entity\n");
1312 //speed = PRVM_G_FLOAT(OFS_PARM1);
1314 VectorCopy (PRVM_serveredictvector(ent, origin), start);
1317 // try sending a trace straight
1318 VectorCopy (PRVM_serverglobalvector(v_forward), dir);
1319 VectorMA (start, 2048, dir, end);
1320 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1321 if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
1322 && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
1324 VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1329 // try all possible entities
1330 VectorCopy (dir, bestdir);
1331 bestdist = sv_aim.value;
1334 check = PRVM_NEXT_EDICT(prog->edicts);
1335 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1337 prog->xfunction->builtinsprofile++;
1338 if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
1342 if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
1343 continue; // don't aim at teammate
1344 for (j=0 ; j<3 ; j++)
1345 end[j] = PRVM_serveredictvector(check, origin)[j]
1346 + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
1347 VectorSubtract (end, start, dir);
1348 VectorNormalize (dir);
1349 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1350 if (dist < bestdist)
1351 continue; // to far to turn
1352 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1353 if (tr.ent == check)
1354 { // can shoot at this one
1362 VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
1363 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1364 VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
1366 VectorNormalize (end);
1367 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1371 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1376 ===============================================================================
1380 ===============================================================================
1383 #define MSG_BROADCAST 0 // unreliable to all
1384 #define MSG_ONE 1 // reliable to one (msg_entity)
1385 #define MSG_ALL 2 // reliable to all
1386 #define MSG_INIT 3 // write to the init string
1387 #define MSG_ENTITY 5
1389 static sizebuf_t *WriteDest(prvm_prog_t *prog)
1395 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1399 return &sv.datagram;
1402 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
1403 entnum = PRVM_NUM_FOR_EDICT(ent);
1404 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1406 VM_Warning(prog, "WriteDest: tried to write to non-client\n");
1407 return &sv.reliable_datagram;
1410 return &svs.clients[entnum-1].netconnection->message;
1413 VM_Warning(prog, "WriteDest: bad destination\n");
1415 return &sv.reliable_datagram;
1421 return sv.writeentitiestoclient_msg;
1427 static void VM_SV_WriteByte(prvm_prog_t *prog)
1429 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1430 MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1433 static void VM_SV_WriteChar(prvm_prog_t *prog)
1435 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1436 MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1439 static void VM_SV_WriteShort(prvm_prog_t *prog)
1441 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1442 MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1445 static void VM_SV_WriteLong(prvm_prog_t *prog)
1447 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1448 MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1451 static void VM_SV_WriteAngle(prvm_prog_t *prog)
1453 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1454 MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1457 static void VM_SV_WriteCoord(prvm_prog_t *prog)
1459 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1460 MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1463 static void VM_SV_WriteString(prvm_prog_t *prog)
1465 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1466 MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1469 static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
1471 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1472 MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1476 static void VM_SV_WriteEntity(prvm_prog_t *prog)
1478 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1479 MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
1482 // writes a picture as at most size bytes of data
1484 // IMGNAME \0 SIZE(short) IMGDATA
1485 // if failed to read/compress:
1487 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1488 static void VM_SV_WritePicture(prvm_prog_t *prog)
1490 const char *imgname;
1494 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1496 imgname = PRVM_G_STRING(OFS_PARM1);
1497 size = (size_t) PRVM_G_FLOAT(OFS_PARM2);
1501 MSG_WriteString(WriteDest(prog), imgname);
1502 if(Image_Compress(imgname, size, &buf, &size))
1505 MSG_WriteShort(WriteDest(prog), (int)size);
1506 SZ_Write(WriteDest(prog), (unsigned char *) buf, (int)size);
1511 MSG_WriteShort(WriteDest(prog), 0);
1515 //////////////////////////////////////////////////////////
1517 static void VM_SV_makestatic(prvm_prog_t *prog)
1522 // allow 0 parameters due to an id1 qc bug in which this function is used
1523 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1524 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1526 if (prog->argc >= 1)
1527 ent = PRVM_G_EDICT(OFS_PARM0);
1529 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1530 if (ent == prog->edicts)
1532 VM_Warning(prog, "makestatic: can not modify world entity\n");
1535 if (ent->priv.server->free)
1537 VM_Warning(prog, "makestatic: can not modify free entity\n");
1542 if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
1547 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1548 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1549 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1551 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1553 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1554 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1555 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1559 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1560 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1561 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1564 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
1565 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
1566 for (i=0 ; i<3 ; i++)
1568 MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
1569 MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
1572 // throw the entity away now
1573 PRVM_ED_Free(prog, ent);
1576 //=============================================================================
1583 static void VM_SV_setspawnparms(prvm_prog_t *prog)
1589 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1591 ent = PRVM_G_EDICT(OFS_PARM0);
1592 i = PRVM_NUM_FOR_EDICT(ent);
1593 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1595 Con_Print("tried to setspawnparms on a non-client\n");
1599 // copy spawn parms out of the client_t
1600 client = svs.clients + i-1;
1601 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1602 (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
1609 Returns a color vector indicating the lighting at the requested point.
1611 (Internal Operation note: actually measures the light beneath the point, just like
1612 the model lighting on the client)
1617 static void VM_SV_getlight(prvm_prog_t *prog)
1619 vec3_t ambientcolor, diffusecolor, diffusenormal;
1621 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1622 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
1623 VectorClear(ambientcolor);
1624 VectorClear(diffusecolor);
1625 VectorClear(diffusenormal);
1626 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1627 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1628 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1633 unsigned char type; // 1/2/8 or 0 to indicate unused
1637 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)
1638 static int vm_customstats_last;
1640 void VM_CustomStats_Clear (void)
1642 memset(vm_customstats, 0, sizeof(vm_customstats));
1643 vm_customstats_last = -1;
1646 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1648 prvm_prog_t *prog = SVVM_prog;
1656 for(i=MIN_VM_STAT; i<=vm_customstats_last ;i++)
1658 if(!vm_customstats[i].type)
1660 switch(vm_customstats[i].type)
1662 //string as 16 bytes
1665 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1666 stats[i] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1667 stats[i+1] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1668 stats[i+2] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1669 stats[i+3] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1671 //float field sent as-is
1673 // 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
1674 u.f = PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1677 //integer value of float field
1679 stats[i] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1687 extern cvar_t sv_gameplayfix_customstats;
1689 // void(float index, float type, .void field) SV_AddStat = #232;
1690 // Set up an auto-sent player stat.
1691 // Client's get thier own fields sent to them. Index may not be less than 32.
1692 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1693 // 1: string (4 stats carrying a total of 16 charactures)
1694 // 2: float (one stat, float converted to an integer for transportation)
1695 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1696 static void VM_SV_AddStat(prvm_prog_t *prog)
1700 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1702 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1703 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1704 off = PRVM_G_INT (OFS_PARM2);
1713 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);
1719 VM_Warning(prog, "PF_SV_AddStat: index (%i) may not be less than %i\n", i, MIN_VM_STAT);
1723 if (i >= MAX_CL_STATS)
1725 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);
1729 if (i > (MAX_CL_STATS - 4) && type == 1)
1731 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);
1735 // these are hazardous to override but sort of allowed if one wants to be adventurous... and enjoys warnings.
1736 if (i < MIN_VM_STAT)
1737 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);
1738 else if (i >= MAX_VM_STAT && !sv_gameplayfix_customstats.integer)
1739 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);
1740 else if (i > (MAX_VM_STAT - 4) && type == 1 && !sv_gameplayfix_customstats.integer)
1741 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);
1743 vm_customstats[i].type = type;
1744 vm_customstats[i].fieldoffset = off;
1745 if(vm_customstats_last < i)
1746 vm_customstats_last = i;
1753 copies data from one entity to another
1755 copyentity(src, dst)
1758 static void VM_SV_copyentity(prvm_prog_t *prog)
1760 prvm_edict_t *in, *out;
1761 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1762 in = PRVM_G_EDICT(OFS_PARM0);
1763 if (in == prog->edicts)
1765 VM_Warning(prog, "copyentity: can not read world entity\n");
1768 if (in->priv.server->free)
1770 VM_Warning(prog, "copyentity: can not read free entity\n");
1773 out = PRVM_G_EDICT(OFS_PARM1);
1774 if (out == prog->edicts)
1776 VM_Warning(prog, "copyentity: can not modify world entity\n");
1779 if (out->priv.server->free)
1781 VM_Warning(prog, "copyentity: can not modify free entity\n");
1784 memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
1785 if (VectorCompare(PRVM_serveredictvector(out, absmin), PRVM_serveredictvector(out, absmax)))
1795 sets the color of a client and broadcasts the update to all connected clients
1797 setcolor(clientent, value)
1800 static void VM_SV_setcolor(prvm_prog_t *prog)
1805 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1806 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1807 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1809 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1811 Con_Print("tried to setcolor a non-client\n");
1815 client = svs.clients + entnum-1;
1818 PRVM_serveredictfloat(client->edict, clientcolors) = i;
1819 PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
1822 if (client->old_colors != client->colors)
1824 client->old_colors = client->colors;
1825 // send notification to all clients
1826 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1827 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1828 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1836 effect(origin, modelname, startframe, framecount, framerate)
1839 static void VM_SV_effect(prvm_prog_t *prog)
1844 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1845 s = PRVM_G_STRING(OFS_PARM1);
1848 VM_Warning(prog, "effect: no model specified\n");
1852 i = SV_ModelIndex(s, 1);
1855 VM_Warning(prog, "effect: model not precached\n");
1859 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1861 VM_Warning(prog, "effect: framecount < 1\n");
1865 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1867 VM_Warning(prog, "effect: framerate < 1\n");
1871 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1872 SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1875 static void VM_SV_te_blood(prvm_prog_t *prog)
1877 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1878 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1880 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1881 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1885 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1887 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1888 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1889 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1891 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1892 SV_FlushBroadcastMessages();
1895 static void VM_SV_te_bloodshower(prvm_prog_t *prog)
1897 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1898 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1900 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1901 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1903 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1904 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1905 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1908 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1909 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1913 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1914 SV_FlushBroadcastMessages();
1917 static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
1919 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1920 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1921 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1923 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1924 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1925 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1927 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1928 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1929 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1930 SV_FlushBroadcastMessages();
1933 static void VM_SV_te_particlecube(prvm_prog_t *prog)
1935 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1936 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1938 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1939 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1941 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1942 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1943 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1945 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1946 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1947 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1949 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1950 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1951 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1953 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1955 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1956 // gravity true/false
1957 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1959 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1960 SV_FlushBroadcastMessages();
1963 static void VM_SV_te_particlerain(prvm_prog_t *prog)
1965 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1966 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1968 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1969 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1971 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1972 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1973 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1976 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1977 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1979 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1980 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1981 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1983 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1985 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1986 SV_FlushBroadcastMessages();
1989 static void VM_SV_te_particlesnow(prvm_prog_t *prog)
1991 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1992 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1994 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1995 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1997 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1998 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1999 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2002 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2003 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2005 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2006 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2007 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2009 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2011 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2012 SV_FlushBroadcastMessages();
2015 static void VM_SV_te_spark(prvm_prog_t *prog)
2017 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
2018 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2020 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2021 MSG_WriteByte(&sv.datagram, TE_SPARK);
2023 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2024 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2025 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2027 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2028 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2029 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2031 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2032 SV_FlushBroadcastMessages();
2035 static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
2037 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
2038 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2039 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2041 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2042 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2043 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2044 SV_FlushBroadcastMessages();
2047 static void VM_SV_te_spikequad(prvm_prog_t *prog)
2049 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2050 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2051 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2053 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2054 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2055 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2056 SV_FlushBroadcastMessages();
2059 static void VM_SV_te_superspikequad(prvm_prog_t *prog)
2061 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2062 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2063 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2065 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2066 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2067 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2068 SV_FlushBroadcastMessages();
2071 static void VM_SV_te_explosionquad(prvm_prog_t *prog)
2073 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2074 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2075 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2077 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2078 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2079 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2080 SV_FlushBroadcastMessages();
2083 static void VM_SV_te_smallflash(prvm_prog_t *prog)
2085 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2086 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2087 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2089 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2090 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2091 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2092 SV_FlushBroadcastMessages();
2095 static void VM_SV_te_customflash(prvm_prog_t *prog)
2097 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2098 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2100 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2101 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2103 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2104 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2105 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2107 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2109 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2111 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2112 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2113 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2114 SV_FlushBroadcastMessages();
2117 static void VM_SV_te_gunshot(prvm_prog_t *prog)
2119 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2120 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2121 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2123 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2124 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2125 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2126 SV_FlushBroadcastMessages();
2129 static void VM_SV_te_spike(prvm_prog_t *prog)
2131 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2132 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2133 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2135 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2136 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2137 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2138 SV_FlushBroadcastMessages();
2141 static void VM_SV_te_superspike(prvm_prog_t *prog)
2143 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2144 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2145 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2147 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2148 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2149 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2150 SV_FlushBroadcastMessages();
2153 static void VM_SV_te_explosion(prvm_prog_t *prog)
2155 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2156 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2157 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2159 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2160 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2161 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2162 SV_FlushBroadcastMessages();
2165 static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
2167 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2168 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2169 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2171 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2172 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2173 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2174 SV_FlushBroadcastMessages();
2177 static void VM_SV_te_wizspike(prvm_prog_t *prog)
2179 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2180 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2181 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2185 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2186 SV_FlushBroadcastMessages();
2189 static void VM_SV_te_knightspike(prvm_prog_t *prog)
2191 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2192 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2193 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2195 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2196 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2197 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2198 SV_FlushBroadcastMessages();
2201 static void VM_SV_te_lavasplash(prvm_prog_t *prog)
2203 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2204 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2205 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2207 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2208 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2209 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2210 SV_FlushBroadcastMessages();
2213 static void VM_SV_te_teleport(prvm_prog_t *prog)
2215 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2216 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2217 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2221 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2222 SV_FlushBroadcastMessages();
2225 static void VM_SV_te_explosion2(prvm_prog_t *prog)
2227 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2228 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2229 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2231 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2232 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2233 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2235 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2236 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2237 SV_FlushBroadcastMessages();
2240 static void VM_SV_te_lightning1(prvm_prog_t *prog)
2242 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2243 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2244 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2246 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2248 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2249 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2250 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2252 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2253 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2254 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2255 SV_FlushBroadcastMessages();
2258 static void VM_SV_te_lightning2(prvm_prog_t *prog)
2260 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2261 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2262 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2264 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2266 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2267 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2268 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2272 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2273 SV_FlushBroadcastMessages();
2276 static void VM_SV_te_lightning3(prvm_prog_t *prog)
2278 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2279 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2280 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2282 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2284 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2285 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2288 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2290 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2291 SV_FlushBroadcastMessages();
2294 static void VM_SV_te_beam(prvm_prog_t *prog)
2296 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2297 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2298 MSG_WriteByte(&sv.datagram, TE_BEAM);
2300 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2302 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2309 SV_FlushBroadcastMessages();
2312 static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
2314 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2315 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2316 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2317 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2318 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2319 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2320 SV_FlushBroadcastMessages();
2323 static void VM_SV_te_flamejet(prvm_prog_t *prog)
2325 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2326 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2327 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2329 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2334 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2335 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2337 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2338 SV_FlushBroadcastMessages();
2341 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2342 //this function originally written by KrimZon, made shorter by LadyHavoc
2343 static void VM_SV_clientcommand(prvm_prog_t *prog)
2345 client_t *temp_client;
2347 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2349 //find client for this entity
2350 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2351 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2353 Con_Print("PF_clientcommand: entity is not a client\n");
2357 temp_client = host_client;
2358 host_client = svs.clients + i;
2359 Cmd_ExecuteString(&cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
2360 host_client = temp_client;
2363 //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)
2364 static void VM_SV_setattachment(prvm_prog_t *prog)
2366 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2367 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2368 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2371 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2373 if (e == prog->edicts)
2375 VM_Warning(prog, "setattachment: can not modify world entity\n");
2378 if (e->priv.server->free)
2380 VM_Warning(prog, "setattachment: can not modify free entity\n");
2384 if (tagentity == NULL)
2385 tagentity = prog->edicts;
2389 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2391 model = SV_GetModelFromEdict(tagentity);
2394 tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
2396 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);
2399 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));
2402 PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
2403 PRVM_serveredictfloat(e, tag_index) = tagindex;
2406 /////////////////////////////////////////
2407 // DP_MD3_TAGINFO extension coded by VorteX
2409 static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
2413 i = (int)PRVM_serveredictfloat(e, modelindex);
2414 if (i < 1 || i >= MAX_MODELS)
2417 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
2420 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2427 Matrix4x4_CreateIdentity(tag_localmatrix);
2429 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2431 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2442 void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix)
2445 float pitchsign = 1;
2447 scale = PRVM_serveredictfloat(ent, scale);
2452 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);
2455 pitchsign = SV_GetPitchSign(prog, ent);
2456 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);
2460 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2463 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2465 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2466 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2467 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2468 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2470 *out = identitymatrix;
2474 // Warnings/errors code:
2475 // 0 - normal (everything all-right)
2478 // 3 - null or non-precached model
2479 // 4 - no tags with requested index
2480 // 5 - runaway loop at attachment chain
2481 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2484 int modelindex, attachloop;
2485 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2488 *out = identitymatrix; // warnings and errors return identical matrix
2490 if (ent == prog->edicts)
2492 if (ent->priv.server->free)
2495 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
2496 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2499 model = SV_GetModelByIndex(modelindex);
2501 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2502 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2503 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2505 tagmatrix = identitymatrix;
2506 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2510 if (attachloop >= 256) // prevent runaway looping
2512 // apply transformation by child's tagindex on parent entity and then
2513 // by parent entity itself
2514 ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
2515 if (ret && attachloop == 0)
2517 SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
2518 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2519 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2520 // next iteration we process the parent entity
2521 if (PRVM_serveredictedict(ent, tag_entity))
2523 tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
2524 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
2531 // RENDER_VIEWMODEL magic
2532 if (PRVM_serveredictedict(ent, viewmodelforclient))
2534 Matrix4x4_Copy(&tagmatrix, out);
2535 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
2537 SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
2538 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2543 //float(entity ent, string tagname) gettagindex;
2545 static void VM_SV_gettagindex(prvm_prog_t *prog)
2548 const char *tag_name;
2551 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2553 ent = PRVM_G_EDICT(OFS_PARM0);
2554 tag_name = PRVM_G_STRING(OFS_PARM1);
2556 if (ent == prog->edicts)
2558 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2561 if (ent->priv.server->free)
2563 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2568 if (!SV_GetModelFromEdict(ent))
2569 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2572 tag_index = SV_GetTagIndex(prog, ent, tag_name);
2574 if(developer_extra.integer)
2575 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2577 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2580 //vector(entity ent, float tagindex) gettaginfo;
2581 static void VM_SV_gettaginfo(prvm_prog_t *prog)
2585 matrix4x4_t tag_matrix;
2586 matrix4x4_t tag_localmatrix;
2588 const char *tagname;
2590 vec3_t forward, left, up, origin;
2591 const model_t *model;
2593 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2595 e = PRVM_G_EDICT(OFS_PARM0);
2596 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2598 returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
2599 Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
2600 VectorCopy(forward, PRVM_serverglobalvector(v_forward));
2601 VectorNegate(left, PRVM_serverglobalvector(v_right));
2602 VectorCopy(up, PRVM_serverglobalvector(v_up));
2603 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
2604 model = SV_GetModelFromEdict(e);
2605 VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
2606 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
2607 VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
2608 SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2609 Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
2611 PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
2612 PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
2613 VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
2614 VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
2615 VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
2616 VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
2621 VM_Warning(prog, "gettagindex: can't affect world entity\n");
2624 VM_Warning(prog, "gettagindex: can't affect free entity\n");
2627 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2630 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2633 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2638 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2639 static void VM_SV_dropclient(prvm_prog_t *prog)
2642 client_t *oldhostclient;
2643 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2644 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2645 if (clientnum < 0 || clientnum >= svs.maxclients)
2647 VM_Warning(prog, "dropclient: not a client\n");
2650 if (!svs.clients[clientnum].active)
2652 VM_Warning(prog, "dropclient: that client slot is not connected\n");
2655 oldhostclient = host_client;
2656 host_client = svs.clients + clientnum;
2657 SV_DropClient(false);
2658 host_client = oldhostclient;
2661 //entity() spawnclient (DP_SV_BOTCLIENT)
2662 static void VM_SV_spawnclient(prvm_prog_t *prog)
2666 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2667 prog->xfunction->builtinsprofile += 2;
2669 for (i = 0;i < svs.maxclients;i++)
2671 if (!svs.clients[i].active)
2673 prog->xfunction->builtinsprofile += 100;
2674 SV_ConnectClient (i, NULL);
2675 // this has to be set or else ClientDisconnect won't be called
2676 // we assume the qc will call ClientConnect...
2677 svs.clients[i].clientconnectcalled = true;
2678 ed = PRVM_EDICT_NUM(i + 1);
2682 VM_RETURN_EDICT(ed);
2685 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2686 static void VM_SV_clienttype(prvm_prog_t *prog)
2689 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2690 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2691 if (clientnum < 0 || clientnum >= svs.maxclients)
2692 PRVM_G_FLOAT(OFS_RETURN) = 3;
2693 else if (!svs.clients[clientnum].active)
2694 PRVM_G_FLOAT(OFS_RETURN) = 0;
2695 else if (svs.clients[clientnum].netconnection)
2696 PRVM_G_FLOAT(OFS_RETURN) = 1;
2698 PRVM_G_FLOAT(OFS_RETURN) = 2;
2705 string(string key) serverkey
2708 static void VM_SV_serverkey(prvm_prog_t *prog)
2710 char string[VM_STRINGTEMP_LENGTH];
2711 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2712 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2713 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2716 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2717 static void VM_SV_setmodelindex(prvm_prog_t *prog)
2722 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2724 e = PRVM_G_EDICT(OFS_PARM0);
2725 if (e == prog->edicts)
2727 VM_Warning(prog, "setmodelindex: can not modify world entity\n");
2730 if (e->priv.server->free)
2732 VM_Warning(prog, "setmodelindex: can not modify free entity\n");
2735 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2736 if (i <= 0 || i >= MAX_MODELS)
2738 VM_Warning(prog, "setmodelindex: invalid modelindex\n");
2741 if (!sv.model_precache[i][0])
2743 VM_Warning(prog, "setmodelindex: model not precached\n");
2747 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2748 PRVM_serveredictfloat(e, modelindex) = i;
2750 mod = SV_GetModelByIndex(i);
2754 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2755 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
2757 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
2760 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
2763 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2764 static void VM_SV_modelnameforindex(prvm_prog_t *prog)
2767 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2769 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2771 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2772 if (i <= 0 || i >= MAX_MODELS)
2774 VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
2777 if (!sv.model_precache[i][0])
2779 VM_Warning(prog, "modelnameforindex: model not precached\n");
2783 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2786 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2787 static void VM_SV_particleeffectnum(prvm_prog_t *prog)
2790 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2791 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2794 PRVM_G_FLOAT(OFS_RETURN) = i;
2797 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2798 static void VM_SV_trailparticles(prvm_prog_t *prog)
2801 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2803 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2806 MSG_WriteByte(&sv.datagram, svc_trailparticles);
2807 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2808 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2809 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2810 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2811 MSG_WriteVector(&sv.datagram, start, sv.protocol);
2812 MSG_WriteVector(&sv.datagram, end, sv.protocol);
2813 SV_FlushBroadcastMessages();
2816 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
2817 static void VM_SV_pointparticles(prvm_prog_t *prog)
2819 int effectnum, count;
2821 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
2823 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2826 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2827 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
2828 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2829 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
2830 if (count == 1 && !VectorLength2(vel))
2833 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
2834 MSG_WriteShort(&sv.datagram, effectnum);
2835 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2839 // 1+2+12+12+2=29 bytes
2840 MSG_WriteByte(&sv.datagram, svc_pointparticles);
2841 MSG_WriteShort(&sv.datagram, effectnum);
2842 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2843 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
2844 MSG_WriteShort(&sv.datagram, count);
2847 SV_FlushBroadcastMessages();
2850 qbool SV_VM_ConsoleCommand (const char *text)
2852 prvm_prog_t *prog = SVVM_prog;
2853 int restorevm_tempstringsbuf_cursize;
2857 if(!sv.active || !prog || !prog->loaded)
2860 if (PRVM_serverfunction(ConsoleCmd))
2862 save_self = PRVM_serverglobaledict(self);
2863 PRVM_serverglobalfloat(time) = sv.time;
2864 restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
2865 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(sv.world.prog->edicts);
2866 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, text);
2867 prog->ExecuteProgram(prog, PRVM_serverfunction(ConsoleCmd), "QC function ConsoleCmd is missing");
2868 prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
2869 PRVM_serverglobaledict(self) = save_self;
2870 r = (int) PRVM_G_FLOAT(OFS_RETURN) != 0;
2875 // #352 void(string cmdname) registercommand (EXT_CSQC)
2876 static void VM_SV_registercommand (prvm_prog_t *prog)
2878 VM_SAFEPARMCOUNT(1, VM_SV_registercmd);
2879 if(!Cmd_Exists(&cmd_server, PRVM_G_STRING(OFS_PARM0)))
2880 Cmd_AddCommand(CF_SERVER, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
2883 //PF_setpause, // void(float pause) setpause = #531;
2884 static void VM_SV_setpause(prvm_prog_t *prog) {
2886 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
2887 if (pauseValue != 0) { //pause the game
2889 sv.pausedstart = host.realtime;
2890 } else { //disable pause, in case it was enabled
2891 if (sv.paused != 0) {
2896 // send notification to all clients
2897 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
2898 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
2901 // #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.
2902 static void VM_SV_skel_create(prvm_prog_t *prog)
2904 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
2905 model_t *model = SV_GetModelByIndex(modelindex);
2906 skeleton_t *skeleton;
2908 PRVM_G_FLOAT(OFS_RETURN) = 0;
2909 if (!model || !model->num_bones)
2911 for (i = 0;i < MAX_EDICTS;i++)
2912 if (!prog->skeletons[i])
2914 if (i == MAX_EDICTS)
2916 prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
2917 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
2918 skeleton->model = model;
2919 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
2920 // initialize to identity matrices
2921 for (i = 0;i < skeleton->model->num_bones;i++)
2922 skeleton->relativetransforms[i] = identitymatrix;
2925 // #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
2926 static void VM_SV_skel_build(prvm_prog_t *prog)
2928 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2929 skeleton_t *skeleton;
2930 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
2931 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
2932 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
2933 int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
2934 int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
2935 model_t *model = SV_GetModelByIndex(modelindex);
2939 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
2940 frameblend_t frameblend[MAX_FRAMEBLENDS];
2941 matrix4x4_t bonematrix;
2943 PRVM_G_FLOAT(OFS_RETURN) = 0;
2944 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2946 firstbone = max(0, firstbone);
2947 lastbone = min(lastbone, model->num_bones - 1);
2948 lastbone = min(lastbone, skeleton->model->num_bones - 1);
2949 VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
2950 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
2951 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
2953 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
2955 memset(&bonematrix, 0, sizeof(bonematrix));
2956 for (blendindex = 0;blendindex < numblends;blendindex++)
2958 Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
2959 Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
2961 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
2962 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
2964 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
2967 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
2968 static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
2970 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2971 skeleton_t *skeleton;
2972 PRVM_G_FLOAT(OFS_RETURN) = 0;
2973 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2975 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
2978 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
2979 static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
2981 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2982 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2983 skeleton_t *skeleton;
2984 PRVM_G_INT(OFS_RETURN) = 0;
2985 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2987 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2989 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
2992 // #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)
2993 static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
2995 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2996 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2997 skeleton_t *skeleton;
2998 PRVM_G_FLOAT(OFS_RETURN) = 0;
2999 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3001 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3003 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3006 // #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
3007 static void VM_SV_skel_find_bone(prvm_prog_t *prog)
3009 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3010 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3011 skeleton_t *skeleton;
3012 PRVM_G_FLOAT(OFS_RETURN) = 0;
3013 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3015 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3018 // #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)
3019 static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
3021 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3022 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3023 skeleton_t *skeleton;
3025 vec3_t forward, left, up, origin;
3026 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3027 VectorClear(PRVM_clientglobalvector(v_forward));
3028 VectorClear(PRVM_clientglobalvector(v_right));
3029 VectorClear(PRVM_clientglobalvector(v_up));
3030 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3032 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3034 matrix = skeleton->relativetransforms[bonenum];
3035 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3036 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3037 VectorNegate(left, PRVM_clientglobalvector(v_right));
3038 VectorCopy(up, PRVM_clientglobalvector(v_up));
3039 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3042 // #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)
3043 static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
3045 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3046 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3047 skeleton_t *skeleton;
3050 vec3_t forward, left, up, origin;
3051 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3052 VectorClear(PRVM_clientglobalvector(v_forward));
3053 VectorClear(PRVM_clientglobalvector(v_right));
3054 VectorClear(PRVM_clientglobalvector(v_up));
3055 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3057 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3059 matrix = skeleton->relativetransforms[bonenum];
3060 // convert to absolute
3061 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3064 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3066 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3067 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3068 VectorNegate(left, PRVM_clientglobalvector(v_right));
3069 VectorCopy(up, PRVM_clientglobalvector(v_up));
3070 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3073 // #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)
3074 static void VM_SV_skel_set_bone(prvm_prog_t *prog)
3076 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3077 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3078 vec3_t forward, left, up, origin;
3079 skeleton_t *skeleton;
3081 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3083 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3085 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3086 VectorNegate(PRVM_clientglobalvector(v_right), left);
3087 VectorCopy(PRVM_clientglobalvector(v_up), up);
3088 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3089 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3090 skeleton->relativetransforms[bonenum] = matrix;
3093 // #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)
3094 static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
3096 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3097 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3098 vec3_t forward, left, up, origin;
3099 skeleton_t *skeleton;
3102 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3104 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3106 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3107 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3108 VectorNegate(PRVM_clientglobalvector(v_right), left);
3109 VectorCopy(PRVM_clientglobalvector(v_up), up);
3110 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3111 temp = skeleton->relativetransforms[bonenum];
3112 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3115 // #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)
3116 static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
3118 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3119 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3120 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3122 vec3_t forward, left, up, origin;
3123 skeleton_t *skeleton;
3126 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3128 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3129 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3130 VectorNegate(PRVM_clientglobalvector(v_right), left);
3131 VectorCopy(PRVM_clientglobalvector(v_up), up);
3132 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3133 firstbone = max(0, firstbone);
3134 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3135 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3137 temp = skeleton->relativetransforms[bonenum];
3138 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3142 // #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
3143 static void VM_SV_skel_copybones(prvm_prog_t *prog)
3145 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3146 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3147 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3148 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3150 skeleton_t *skeletondst;
3151 skeleton_t *skeletonsrc;
3152 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3154 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3156 firstbone = max(0, firstbone);
3157 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3158 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3159 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3160 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3163 // #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)
3164 static void VM_SV_skel_delete(prvm_prog_t *prog)
3166 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3167 skeleton_t *skeleton;
3168 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3171 prog->skeletons[skeletonindex] = NULL;
3174 // #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
3175 static void VM_SV_frameforname(prvm_prog_t *prog)
3177 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3178 model_t *model = SV_GetModelByIndex(modelindex);
3179 const char *name = PRVM_G_STRING(OFS_PARM1);
3181 PRVM_G_FLOAT(OFS_RETURN) = -1;
3182 if (!model || !model->animscenes)
3184 for (i = 0;i < model->numframes;i++)
3186 if (!strcasecmp(model->animscenes[i].name, name))
3188 PRVM_G_FLOAT(OFS_RETURN) = i;
3194 // #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.
3195 static void VM_SV_frameduration(prvm_prog_t *prog)
3197 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3198 model_t *model = SV_GetModelByIndex(modelindex);
3199 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3200 PRVM_G_FLOAT(OFS_RETURN) = 0;
3201 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3203 if (model->animscenes[framenum].framerate)
3204 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3208 prvm_builtin_t vm_sv_builtins[] = {
3209 NULL, // #0 NULL function (not callable) (QUAKE)
3210 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3211 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3212 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3213 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3214 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3215 VM_break, // #6 void() break (QUAKE)
3216 VM_random, // #7 float() random (QUAKE)
3217 VM_SV_sound, // #8 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
3218 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3219 VM_error, // #10 void(string e) error (QUAKE)
3220 VM_objerror, // #11 void(string e) objerror (QUAKE)
3221 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3222 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3223 VM_spawn, // #14 entity() spawn (QUAKE)
3224 VM_remove, // #15 void(entity e) remove (QUAKE)
3225 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3226 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3227 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3228 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3229 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3230 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3231 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3232 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3233 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3234 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3235 VM_ftos, // #26 string(float f) ftos (QUAKE)
3236 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3237 VM_coredump, // #28 void() coredump (QUAKE)
3238 VM_traceon, // #29 void() traceon (QUAKE)
3239 VM_traceoff, // #30 void() traceoff (QUAKE)
3240 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3241 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3242 NULL, // #33 (QUAKE)
3243 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3244 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3245 VM_rint, // #36 float(float v) rint (QUAKE)
3246 VM_floor, // #37 float(float v) floor (QUAKE)
3247 VM_ceil, // #38 float(float v) ceil (QUAKE)
3248 NULL, // #39 (QUAKE)
3249 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3250 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3251 NULL, // #42 (QUAKE)
3252 VM_fabs, // #43 float(float f) fabs (QUAKE)
3253 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3254 VM_cvar, // #45 float(string s) cvar (QUAKE)
3255 VM_localcmd_server, // #46 void(string s) localcmd (QUAKE)
3256 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3257 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3258 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3259 NULL, // #50 (QUAKE)
3260 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3261 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3262 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3263 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3264 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3265 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3266 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3267 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3268 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3269 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3270 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3271 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3272 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3273 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3274 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3275 NULL, // #66 (QUAKE)
3276 VM_SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3277 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3278 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3279 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3280 NULL, // #71 (QUAKE)
3281 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3282 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3283 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3284 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3285 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3286 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3287 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3288 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3289 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3290 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3291 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3292 NULL, // #83 (QUAKE)
3293 NULL, // #84 (QUAKE)
3294 NULL, // #85 (QUAKE)
3295 NULL, // #86 (QUAKE)
3296 NULL, // #87 (QUAKE)
3297 NULL, // #88 (QUAKE)
3298 NULL, // #89 (QUAKE)
3299 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3300 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3301 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3302 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3303 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3304 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3305 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3306 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3307 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3308 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3309 // FrikaC and Telejano range #100-#199
3320 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3321 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3322 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3323 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3324 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3325 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3326 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3327 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3328 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3329 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3410 // FTEQW range #200-#299
3429 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3432 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3433 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3434 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3435 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3436 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3437 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3438 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3439 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3440 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3441 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3443 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3451 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3474 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.
3475 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
3476 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3477 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3478 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)
3479 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
3480 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)
3481 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)
3482 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)
3483 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)
3484 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)
3485 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
3486 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)
3487 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
3488 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.
3511 // CSQC range #300-#399
3512 NULL, // #300 void() clearscene (EXT_CSQC)
3513 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3514 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3515 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3516 NULL, // #304 void() renderscene (EXT_CSQC)
3517 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3518 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3519 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3520 NULL, // #308 void() R_EndPolygon
3522 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3523 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3527 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3528 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3529 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3530 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3531 NULL, // #319 void(string name) freepic (EXT_CSQC)
3532 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3533 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3534 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3535 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3536 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3537 NULL, // #325 void(void) drawresetcliparea
3542 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3543 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3544 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3545 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3546 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3547 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3548 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3549 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3550 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3551 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3552 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3553 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3554 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3555 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3556 NULL, // #344 vector() getmousepos (EXT_CSQC)
3557 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3558 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3559 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3560 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3561 NULL, // #349 float() isdemo (EXT_CSQC)
3562 VM_isserver, // #350 float() isserver (EXT_CSQC)
3563 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3564 VM_SV_registercommand, // #352 void(string cmdname) registercommand (EXT_CSQC)
3565 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3566 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3572 NULL, // #360 float() readbyte (EXT_CSQC)
3573 NULL, // #361 float() readchar (EXT_CSQC)
3574 NULL, // #362 float() readshort (EXT_CSQC)
3575 NULL, // #363 float() readlong (EXT_CSQC)
3576 NULL, // #364 float() readcoord (EXT_CSQC)
3577 NULL, // #365 float() readangle (EXT_CSQC)
3578 NULL, // #366 string() readstring (EXT_CSQC)
3579 NULL, // #367 float() readfloat (EXT_CSQC)
3612 // LadyHavoc's range #400-#499
3613 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3614 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3615 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3616 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3617 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3618 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3619 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3620 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3621 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)
3622 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3623 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3624 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3625 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3626 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3627 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3628 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3629 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3630 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3631 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3632 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3633 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3634 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3635 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3636 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3637 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3638 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3639 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3640 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3641 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3642 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3643 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3644 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3645 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3646 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3647 VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3648 VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3649 VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3650 VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3651 VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3652 VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3653 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3654 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3655 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3656 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3657 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3658 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3659 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3660 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3661 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3662 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3663 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3664 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3665 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3666 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3667 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3668 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3669 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3670 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3672 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3673 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3674 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3675 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3676 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3677 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3678 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3679 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3680 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3681 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3682 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3684 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3685 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3686 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3687 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3688 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3689 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3690 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3691 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3692 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3693 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3694 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3695 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3696 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3697 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3698 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3699 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3707 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3708 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3709 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3710 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3711 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3712 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3713 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3714 VM_SV_WritePicture, // #501
3716 VM_whichpack, // #503 string(string) whichpack = #503;
3723 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3724 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3725 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3726 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)
3727 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3728 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3729 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3730 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3731 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3732 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3742 VM_loadfromdata, // #529
3743 VM_loadfromfile, // #530
3744 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3746 VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
3747 VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
3748 VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
3749 VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
3750 VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
3751 VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
3753 VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
3754 VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
3755 VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
3818 VM_callfunction, // #605
3819 VM_writetofile, // #606
3820 VM_isfunction, // #607
3826 VM_parseentitydata, // #613
3837 VM_SV_getextresponse, // #624 string getextresponse(void)
3840 VM_sprintf, // #627 string sprintf(string format, ...)
3841 VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
3842 VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
3852 VM_digest_hex, // #639
3855 VM_coverage, // #642
3859 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
3861 void SVVM_init_cmd(prvm_prog_t *prog)
3866 void SVVM_reset_cmd(prvm_prog_t *prog)
3868 World_End(&sv.world);
3870 if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
3872 func_t s = PRVM_serverfunction(SV_Shutdown);
3873 PRVM_serverglobalfloat(time) = sv.time;
3874 PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
3875 prog->ExecuteProgram(prog, s,"SV_Shutdown() required");