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 if(sv.protocol == PROTOCOL_NEHAHRABJP)
494 // add an svc_spawnambient command to the level signon packet
497 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
499 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
501 MSG_WriteVector(&sv.signon, pos, sv.protocol);
503 if (large || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
504 MSG_WriteShort (&sv.signon, soundnum);
506 MSG_WriteByte (&sv.signon, soundnum);
508 MSG_WriteByte (&sv.signon, (int)(vol*255));
509 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
517 Each entity can have eight independant sound sources, like voice,
520 Channel 0 is an auto-allocate channel, the others override anything
521 already running on that entity/channel pair.
523 An attenuation of 0 will play full volume everywhere in the level.
524 Larger attenuations will drop off.
526 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
529 static void VM_SV_sound(prvm_prog_t *prog)
533 prvm_edict_t *entity;
539 VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
541 entity = PRVM_G_EDICT(OFS_PARM0);
542 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
543 sample = PRVM_G_STRING(OFS_PARM2);
544 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
547 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
551 attenuation = PRVM_G_FLOAT(OFS_PARM4);
555 pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
560 if(channel >= 8 && channel <= 15) // weird QW feature
562 flags |= CHANNELFLAG_RELIABLE;
568 // LadyHavoc: we only let the qc set certain flags, others are off-limits
569 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
572 if (nvolume < 0 || nvolume > 255)
574 VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
578 if (attenuation < 0 || attenuation > 4)
580 VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
584 channel = CHAN_USER2ENGINE(channel);
586 if (!IS_CHAN(channel))
588 VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
592 SV_StartSound (entity, channel, sample, nvolume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange);
599 Follows the same logic as VM_SV_sound, except instead of
600 an entity, an origin for the sound is provided, and channel
601 is omitted (since no entity is being tracked).
605 static void VM_SV_pointsound(prvm_prog_t *prog)
613 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
615 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
616 sample = PRVM_G_STRING(OFS_PARM1);
617 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
618 attenuation = PRVM_G_FLOAT(OFS_PARM3);
619 pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
621 if (nvolume < 0 || nvolume > 255)
623 VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
627 if (attenuation < 0 || attenuation > 4)
629 VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
633 SV_StartPointSound (org, sample, nvolume, attenuation, pitchchange);
640 Used for use tracing and shot targeting
641 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
642 if the tryents flag is set.
644 traceline (vector1, vector2, movetype, ignore)
647 static void VM_SV_traceline(prvm_prog_t *prog)
654 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
656 prog->xfunction->builtinsprofile += 30;
658 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
659 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
660 move = (int)PRVM_G_FLOAT(OFS_PARM2);
661 ent = PRVM_G_EDICT(OFS_PARM3);
663 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]))
664 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));
666 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value);
668 VM_SetTraceGlobals(prog, &trace);
676 Used for use tracing and shot targeting
677 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
678 if the tryents flag is set.
680 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
683 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
684 static void VM_SV_tracebox(prvm_prog_t *prog)
686 vec3_t v1, v2, m1, m2;
691 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
693 prog->xfunction->builtinsprofile += 30;
695 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
696 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
697 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
698 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
699 move = (int)PRVM_G_FLOAT(OFS_PARM4);
700 ent = PRVM_G_EDICT(OFS_PARM5);
702 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]))
703 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));
705 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value);
707 VM_SetTraceGlobals(prog, &trace);
710 static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
714 vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
715 vec3_t original_origin;
716 vec3_t original_velocity;
717 vec3_t original_angles;
718 vec3_t original_avelocity;
721 VectorCopy(PRVM_serveredictvector(tossent, origin) , original_origin );
722 VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
723 VectorCopy(PRVM_serveredictvector(tossent, angles) , original_angles );
724 VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
726 gravity = PRVM_serveredictfloat(tossent, gravity);
729 gravity *= sv_gravity.value * 0.025;
731 for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
733 SV_CheckVelocity (tossent);
734 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
735 VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
736 VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
737 VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
738 VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
739 VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
740 VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
741 trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value);
742 VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
743 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
745 if (trace.fraction < 1)
749 VectorCopy(original_origin , PRVM_serveredictvector(tossent, origin) );
750 VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
751 VectorCopy(original_angles , PRVM_serveredictvector(tossent, angles) );
752 VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
757 static void VM_SV_tracetoss(prvm_prog_t *prog)
761 prvm_edict_t *ignore;
763 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
765 prog->xfunction->builtinsprofile += 600;
767 ent = PRVM_G_EDICT(OFS_PARM0);
768 if (ent == prog->edicts)
770 VM_Warning(prog, "tracetoss: can not use world entity\n");
773 ignore = PRVM_G_EDICT(OFS_PARM1);
775 trace = SV_Trace_Toss(prog, ent, ignore);
777 VM_SetTraceGlobals(prog, &trace);
780 //============================================================================
782 static int checkpvsbytes;
783 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
785 static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
791 // cycle to the next one
793 check = bound(1, check, svs.maxclients);
794 if (check == svs.maxclients)
802 prog->xfunction->builtinsprofile++;
804 if (i == svs.maxclients+1)
806 // look up the client's edict
807 ent = PRVM_EDICT_NUM(i);
808 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
809 if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
811 // found a valid client (possibly the same one again)
815 // get the PVS for the entity
816 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
818 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
819 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
828 Returns a client (or object that has a client enemy) that would be a
831 If there is more than one valid option, they are cycled each frame
833 If (self.origin + self.viewofs) is not in the PVS of the current target,
834 it is not returned at all.
839 int c_invis, c_notvis;
840 static void VM_SV_checkclient(prvm_prog_t *prog)
842 prvm_edict_t *ent, *self;
845 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
847 // find a new check if on a new frame
848 if (sv.time - sv.lastchecktime >= 0.1)
850 sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
851 sv.lastchecktime = sv.time;
854 // return check if it might be visible
855 ent = PRVM_EDICT_NUM(sv.lastcheck);
856 if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
858 VM_RETURN_EDICT(prog->edicts);
862 // if current entity can't possibly see the check entity, return 0
863 self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
864 VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
865 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
868 VM_RETURN_EDICT(prog->edicts);
872 // might be able to see it
874 VM_RETURN_EDICT(ent);
877 //============================================================================
883 Checks if an entity is in a point's PVS.
884 Should be fast but can be inexact.
886 float checkpvs(vector viewpos, entity viewee) = #240;
889 static void VM_SV_checkpvs(prvm_prog_t *prog)
891 vec3_t viewpos, absmin, absmax;
892 prvm_edict_t *viewee;
897 unsigned char fatpvs[MAX_MAP_LEAFS/8];
900 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
901 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
902 viewee = PRVM_G_EDICT(OFS_PARM1);
904 if(viewee->priv.server->free)
906 VM_Warning(prog, "checkpvs: can not check free entity\n");
907 PRVM_G_FLOAT(OFS_RETURN) = 4;
912 if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
914 // no PVS support on this worldmodel... darn
915 PRVM_G_FLOAT(OFS_RETURN) = 3;
918 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
921 // viewpos isn't in any PVS... darn
922 PRVM_G_FLOAT(OFS_RETURN) = 2;
925 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
926 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
927 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
929 // using fat PVS like FTEQW does (slow)
930 if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
932 // no PVS support on this worldmodel... darn
933 PRVM_G_FLOAT(OFS_RETURN) = 3;
936 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
939 // viewpos isn't in any PVS... darn
940 PRVM_G_FLOAT(OFS_RETURN) = 2;
943 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
944 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
945 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
954 Sends text over to the client's execution buffer
956 stuffcmd (clientent, value, ...)
959 static void VM_SV_stuffcmd(prvm_prog_t *prog)
963 char string[VM_STRINGTEMP_LENGTH];
965 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
967 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
968 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
970 VM_Warning(prog, "Can't stuffcmd to a non-client\n");
974 VM_VarString(prog, 1, string, sizeof(string));
977 host_client = svs.clients + entnum-1;
978 SV_ClientCommands ("%s", string);
986 Returns a chain of entities that have origins within a spherical area
988 findradius (origin, radius)
991 static void VM_SV_findradius(prvm_prog_t *prog)
993 prvm_edict_t *ent, *chain;
994 vec_t radius, radius2;
995 vec3_t org, eorg, mins, maxs;
998 static prvm_edict_t *touchedicts[MAX_EDICTS];
1001 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
1004 chainfield = PRVM_G_INT(OFS_PARM2);
1006 chainfield = prog->fieldoffsets.chain;
1008 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
1010 chain = (prvm_edict_t *)prog->edicts;
1012 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1013 radius = PRVM_G_FLOAT(OFS_PARM1);
1014 radius2 = radius * radius;
1016 mins[0] = org[0] - (radius + 1);
1017 mins[1] = org[1] - (radius + 1);
1018 mins[2] = org[2] - (radius + 1);
1019 maxs[0] = org[0] + (radius + 1);
1020 maxs[1] = org[1] + (radius + 1);
1021 maxs[2] = org[2] + (radius + 1);
1022 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1023 if (numtouchedicts > MAX_EDICTS)
1025 // this never happens
1026 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1027 numtouchedicts = MAX_EDICTS;
1029 for (i = 0;i < numtouchedicts;i++)
1031 ent = touchedicts[i];
1032 prog->xfunction->builtinsprofile++;
1033 // Quake did not return non-solid entities but darkplaces does
1034 // (note: this is the reason you can't blow up fallen zombies)
1035 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1037 // LadyHavoc: compare against bounding box rather than center so it
1038 // doesn't miss large objects, and use DotProduct instead of Length
1039 // for a major speedup
1040 VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
1041 if (sv_gameplayfix_findradiusdistancetobox.integer)
1043 eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
1044 eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
1045 eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
1048 VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
1049 if (DotProduct(eorg, eorg) < radius2)
1051 PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
1056 VM_RETURN_EDICT(chain);
1059 static void VM_SV_precache_sound(prvm_prog_t *prog)
1061 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1062 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1065 static void VM_SV_precache_model(prvm_prog_t *prog)
1067 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1068 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1069 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1076 float(float yaw, float dist[, settrace]) walkmove
1079 static void VM_SV_walkmove(prvm_prog_t *prog)
1088 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1090 // assume failure if it returns early
1091 PRVM_G_FLOAT(OFS_RETURN) = 0;
1093 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1094 if (ent == prog->edicts)
1096 VM_Warning(prog, "walkmove: can not modify world entity\n");
1099 if (ent->priv.server->free)
1101 VM_Warning(prog, "walkmove: can not modify free entity\n");
1104 yaw = PRVM_G_FLOAT(OFS_PARM0);
1105 dist = PRVM_G_FLOAT(OFS_PARM1);
1106 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1108 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1111 yaw = yaw*M_PI*2 / 360;
1113 move[0] = cos(yaw)*dist;
1114 move[1] = sin(yaw)*dist;
1117 // save program state, because SV_movestep may call other progs
1118 oldf = prog->xfunction;
1119 oldself = PRVM_serverglobaledict(self);
1121 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1124 // restore program state
1125 prog->xfunction = oldf;
1126 PRVM_serverglobaledict(self) = oldself;
1137 static void VM_SV_droptofloor(prvm_prog_t *prog)
1140 vec3_t end, entorigin, entmins, entmaxs;
1143 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1145 // assume failure if it returns early
1146 PRVM_G_FLOAT(OFS_RETURN) = 0;
1148 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1149 if (ent == prog->edicts)
1151 VM_Warning(prog, "droptofloor: can not modify world entity\n");
1154 if (ent->priv.server->free)
1156 VM_Warning(prog, "droptofloor: can not modify free entity\n");
1160 VectorCopy (PRVM_serveredictvector(ent, origin), end);
1163 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1164 SV_NudgeOutOfSolid(ent);
1166 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
1167 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
1168 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
1169 trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1170 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1173 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]);
1174 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
1175 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1176 VectorSubtract(trace.endpos, offset, trace.endpos);
1177 if (trace.startsolid)
1179 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]);
1181 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1182 PRVM_serveredictedict(ent, groundentity) = 0;
1183 PRVM_G_FLOAT(OFS_RETURN) = 1;
1185 else if (trace.fraction < 1)
1187 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]);
1188 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1189 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1190 SV_NudgeOutOfSolid(ent);
1192 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1193 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1194 PRVM_G_FLOAT(OFS_RETURN) = 1;
1195 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1196 ent->priv.server->suspendedinairflag = true;
1201 if (!trace.allsolid && trace.fraction < 1)
1203 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1205 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1206 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1207 PRVM_G_FLOAT(OFS_RETURN) = 1;
1208 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1209 ent->priv.server->suspendedinairflag = true;
1218 void(float style, string value) lightstyle
1221 static void VM_SV_lightstyle(prvm_prog_t *prog)
1228 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1230 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1231 val = PRVM_G_STRING(OFS_PARM1);
1233 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1234 prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
1237 // change the string in sv
1238 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1240 // send message to all clients on this server
1241 if (sv.state != ss_active)
1244 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1246 if (client->active && client->netconnection)
1248 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1249 MSG_WriteChar (&client->netconnection->message,style);
1250 MSG_WriteString (&client->netconnection->message, val);
1260 static void VM_SV_checkbottom(prvm_prog_t *prog)
1262 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1263 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1271 static void VM_SV_pointcontents(prvm_prog_t *prog)
1274 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1275 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
1276 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(point));
1283 Pick a vector for the player to shoot along
1284 vector aim(entity, missilespeed)
1287 static void VM_SV_aim(prvm_prog_t *prog)
1289 prvm_edict_t *ent, *check, *bestent;
1290 vec3_t start, dir, end, bestdir;
1293 float dist, bestdist;
1296 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1298 // assume failure if it returns early
1299 VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1300 // if sv_aim is so high it can't possibly accept anything, skip out early
1301 if (sv_aim.value >= 1)
1304 ent = PRVM_G_EDICT(OFS_PARM0);
1305 if (ent == prog->edicts)
1307 VM_Warning(prog, "aim: can not use world entity\n");
1310 if (ent->priv.server->free)
1312 VM_Warning(prog, "aim: can not use free entity\n");
1315 //speed = PRVM_G_FLOAT(OFS_PARM1);
1317 VectorCopy (PRVM_serveredictvector(ent, origin), start);
1320 // try sending a trace straight
1321 VectorCopy (PRVM_serverglobalvector(v_forward), dir);
1322 VectorMA (start, 2048, dir, end);
1323 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1324 if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
1325 && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
1327 VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1332 // try all possible entities
1333 VectorCopy (dir, bestdir);
1334 bestdist = sv_aim.value;
1337 check = PRVM_NEXT_EDICT(prog->edicts);
1338 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1340 prog->xfunction->builtinsprofile++;
1341 if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
1345 if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
1346 continue; // don't aim at teammate
1347 for (j=0 ; j<3 ; j++)
1348 end[j] = PRVM_serveredictvector(check, origin)[j]
1349 + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
1350 VectorSubtract (end, start, dir);
1351 VectorNormalize (dir);
1352 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1353 if (dist < bestdist)
1354 continue; // to far to turn
1355 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1356 if (tr.ent == check)
1357 { // can shoot at this one
1365 VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
1366 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1367 VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
1369 VectorNormalize (end);
1370 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1374 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1379 ===============================================================================
1383 ===============================================================================
1386 #define MSG_BROADCAST 0 // unreliable to all
1387 #define MSG_ONE 1 // reliable to one (msg_entity)
1388 #define MSG_ALL 2 // reliable to all
1389 #define MSG_INIT 3 // write to the init string
1390 #define MSG_ENTITY 5
1392 static sizebuf_t *WriteDest(prvm_prog_t *prog)
1398 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1402 return &sv.datagram;
1405 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
1406 entnum = PRVM_NUM_FOR_EDICT(ent);
1407 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1409 VM_Warning(prog, "WriteDest: tried to write to non-client\n");
1410 return &sv.reliable_datagram;
1413 return &svs.clients[entnum-1].netconnection->message;
1416 VM_Warning(prog, "WriteDest: bad destination\n");
1418 return &sv.reliable_datagram;
1424 return sv.writeentitiestoclient_msg;
1430 static void VM_SV_WriteByte(prvm_prog_t *prog)
1432 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1433 MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1436 static void VM_SV_WriteChar(prvm_prog_t *prog)
1438 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1439 MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1442 static void VM_SV_WriteShort(prvm_prog_t *prog)
1444 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1445 MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1448 static void VM_SV_WriteLong(prvm_prog_t *prog)
1450 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1451 MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1454 static void VM_SV_WriteAngle(prvm_prog_t *prog)
1456 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1457 MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1460 static void VM_SV_WriteCoord(prvm_prog_t *prog)
1462 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1463 MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1466 static void VM_SV_WriteString(prvm_prog_t *prog)
1468 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1469 MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1472 static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
1474 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1475 MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1479 static void VM_SV_WriteEntity(prvm_prog_t *prog)
1481 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1482 MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
1485 // writes a picture as at most size bytes of data
1487 // IMGNAME \0 SIZE(short) IMGDATA
1488 // if failed to read/compress:
1490 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1491 static void VM_SV_WritePicture(prvm_prog_t *prog)
1493 const char *imgname;
1497 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1499 imgname = PRVM_G_STRING(OFS_PARM1);
1500 size = (size_t) PRVM_G_FLOAT(OFS_PARM2);
1504 MSG_WriteString(WriteDest(prog), imgname);
1505 if(Image_Compress(imgname, size, &buf, &size))
1508 MSG_WriteShort(WriteDest(prog), (int)size);
1509 SZ_Write(WriteDest(prog), (unsigned char *) buf, (int)size);
1514 MSG_WriteShort(WriteDest(prog), 0);
1518 //////////////////////////////////////////////////////////
1520 static void VM_SV_makestatic(prvm_prog_t *prog)
1525 // allow 0 parameters due to an id1 qc bug in which this function is used
1526 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1527 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1529 if (prog->argc >= 1)
1530 ent = PRVM_G_EDICT(OFS_PARM0);
1532 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1533 if (ent == prog->edicts)
1535 VM_Warning(prog, "makestatic: can not modify world entity\n");
1538 if (ent->priv.server->free)
1540 VM_Warning(prog, "makestatic: can not modify free entity\n");
1545 if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
1548 if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1550 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1551 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1552 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1556 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1557 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1558 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1562 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1563 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1564 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1567 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
1568 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
1569 for (i=0 ; i<3 ; i++)
1571 MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
1572 MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
1575 // throw the entity away now
1576 PRVM_ED_Free(prog, ent);
1579 //=============================================================================
1586 static void VM_SV_setspawnparms(prvm_prog_t *prog)
1592 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1594 ent = PRVM_G_EDICT(OFS_PARM0);
1595 i = PRVM_NUM_FOR_EDICT(ent);
1596 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1598 Con_Print("tried to setspawnparms on a non-client\n");
1602 // copy spawn parms out of the client_t
1603 client = svs.clients + i-1;
1604 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1605 (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
1612 Returns a color vector indicating the lighting at the requested point.
1614 (Internal Operation note: actually measures the light beneath the point, just like
1615 the model lighting on the client)
1620 static void VM_SV_getlight(prvm_prog_t *prog)
1622 vec3_t ambientcolor, diffusecolor, diffusenormal;
1624 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1625 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
1626 VectorClear(ambientcolor);
1627 VectorClear(diffusecolor);
1628 VectorClear(diffusenormal);
1629 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1630 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1631 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1636 unsigned char type; // 1/2/8 or 0 to indicate unused
1640 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)
1641 static int vm_customstats_last;
1643 void VM_CustomStats_Clear (void)
1645 memset(vm_customstats, 0, sizeof(vm_customstats));
1646 vm_customstats_last = -1;
1649 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1651 prvm_prog_t *prog = SVVM_prog;
1659 for(i=MIN_VM_STAT; i<=vm_customstats_last ;i++)
1661 if(!vm_customstats[i].type)
1663 switch(vm_customstats[i].type)
1665 //string as 16 bytes
1668 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1669 stats[i] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1670 stats[i+1] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1671 stats[i+2] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1672 stats[i+3] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1674 //float field sent as-is
1676 // 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
1677 u.f = PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1680 //integer value of float field
1682 stats[i] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1690 extern cvar_t sv_gameplayfix_customstats;
1692 // void(float index, float type, .void field) SV_AddStat = #232;
1693 // Set up an auto-sent player stat.
1694 // Client's get thier own fields sent to them. Index may not be less than 32.
1695 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1696 // 1: string (4 stats carrying a total of 16 charactures)
1697 // 2: float (one stat, float converted to an integer for transportation)
1698 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1699 static void VM_SV_AddStat(prvm_prog_t *prog)
1703 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1705 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1706 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1707 off = PRVM_G_INT (OFS_PARM2);
1716 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);
1722 VM_Warning(prog, "PF_SV_AddStat: index (%i) may not be less than %i\n", i, MIN_VM_STAT);
1726 if (i >= MAX_CL_STATS)
1728 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);
1732 if (i > (MAX_CL_STATS - 4) && type == 1)
1734 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);
1738 // these are hazardous to override but sort of allowed if one wants to be adventurous... and enjoys warnings.
1739 if (i < MIN_VM_STAT)
1740 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);
1741 else if (i >= MAX_VM_STAT && !sv_gameplayfix_customstats.integer)
1742 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);
1743 else if (i > (MAX_VM_STAT - 4) && type == 1 && !sv_gameplayfix_customstats.integer)
1744 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);
1746 vm_customstats[i].type = type;
1747 vm_customstats[i].fieldoffset = off;
1748 if(vm_customstats_last < i)
1749 vm_customstats_last = i;
1756 copies data from one entity to another
1758 copyentity(src, dst)
1761 static void VM_SV_copyentity(prvm_prog_t *prog)
1763 prvm_edict_t *in, *out;
1764 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1765 in = PRVM_G_EDICT(OFS_PARM0);
1766 if (in == prog->edicts)
1768 VM_Warning(prog, "copyentity: can not read world entity\n");
1771 if (in->priv.server->free)
1773 VM_Warning(prog, "copyentity: can not read free entity\n");
1776 out = PRVM_G_EDICT(OFS_PARM1);
1777 if (out == prog->edicts)
1779 VM_Warning(prog, "copyentity: can not modify world entity\n");
1782 if (out->priv.server->free)
1784 VM_Warning(prog, "copyentity: can not modify free entity\n");
1787 memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
1788 if (VectorCompare(PRVM_serveredictvector(out, absmin), PRVM_serveredictvector(out, absmax)))
1798 sets the color of a client and broadcasts the update to all connected clients
1800 setcolor(clientent, value)
1803 static void VM_SV_setcolor(prvm_prog_t *prog)
1808 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1809 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1810 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1812 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1814 Con_Print("tried to setcolor a non-client\n");
1818 client = svs.clients + entnum-1;
1821 PRVM_serveredictfloat(client->edict, clientcolors) = i;
1822 PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
1825 if (client->old_colors != client->colors)
1827 client->old_colors = client->colors;
1828 // send notification to all clients
1829 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1830 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1831 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1839 effect(origin, modelname, startframe, framecount, framerate)
1842 static void VM_SV_effect(prvm_prog_t *prog)
1847 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1848 s = PRVM_G_STRING(OFS_PARM1);
1851 VM_Warning(prog, "effect: no model specified\n");
1855 i = SV_ModelIndex(s, 1);
1858 VM_Warning(prog, "effect: model not precached\n");
1862 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1864 VM_Warning(prog, "effect: framecount < 1\n");
1868 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1870 VM_Warning(prog, "effect: framerate < 1\n");
1874 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1875 SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1878 static void VM_SV_te_blood(prvm_prog_t *prog)
1880 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1881 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1883 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1884 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1886 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1887 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1888 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1890 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1891 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1892 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1894 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1895 SV_FlushBroadcastMessages();
1898 static void VM_SV_te_bloodshower(prvm_prog_t *prog)
1900 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1901 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1903 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1904 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1906 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1908 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1912 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1914 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1916 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1917 SV_FlushBroadcastMessages();
1920 static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
1922 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1923 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1924 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1926 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1927 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1928 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1930 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1931 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1932 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1933 SV_FlushBroadcastMessages();
1936 static void VM_SV_te_particlecube(prvm_prog_t *prog)
1938 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1939 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1941 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1942 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1944 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1945 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1946 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1948 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1949 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1950 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1952 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1953 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1954 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1956 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1958 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1959 // gravity true/false
1960 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1962 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1963 SV_FlushBroadcastMessages();
1966 static void VM_SV_te_particlerain(prvm_prog_t *prog)
1968 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1969 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1971 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1972 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1974 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1976 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1978 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1979 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1980 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1982 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1983 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1984 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1986 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1988 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1989 SV_FlushBroadcastMessages();
1992 static void VM_SV_te_particlesnow(prvm_prog_t *prog)
1994 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1995 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1997 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1998 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2000 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2002 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2004 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2005 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2006 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2008 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2009 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2010 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2012 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2014 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2015 SV_FlushBroadcastMessages();
2018 static void VM_SV_te_spark(prvm_prog_t *prog)
2020 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
2021 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2023 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2024 MSG_WriteByte(&sv.datagram, TE_SPARK);
2026 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2027 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2028 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2030 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2031 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2032 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2034 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2035 SV_FlushBroadcastMessages();
2038 static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
2040 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
2041 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2042 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2044 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2045 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2046 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2047 SV_FlushBroadcastMessages();
2050 static void VM_SV_te_spikequad(prvm_prog_t *prog)
2052 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2053 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2054 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2056 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2057 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2058 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2059 SV_FlushBroadcastMessages();
2062 static void VM_SV_te_superspikequad(prvm_prog_t *prog)
2064 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2065 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2066 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2068 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2069 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2070 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2071 SV_FlushBroadcastMessages();
2074 static void VM_SV_te_explosionquad(prvm_prog_t *prog)
2076 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2077 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2078 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2080 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2081 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2082 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2083 SV_FlushBroadcastMessages();
2086 static void VM_SV_te_smallflash(prvm_prog_t *prog)
2088 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2089 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2090 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2092 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2093 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2094 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2095 SV_FlushBroadcastMessages();
2098 static void VM_SV_te_customflash(prvm_prog_t *prog)
2100 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2101 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2103 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2104 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2106 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2107 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2108 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2110 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2112 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2114 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2115 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2116 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2117 SV_FlushBroadcastMessages();
2120 static void VM_SV_te_gunshot(prvm_prog_t *prog)
2122 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2123 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2124 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2126 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2127 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2128 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2129 SV_FlushBroadcastMessages();
2132 static void VM_SV_te_spike(prvm_prog_t *prog)
2134 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2135 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2136 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2138 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2139 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2140 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2141 SV_FlushBroadcastMessages();
2144 static void VM_SV_te_superspike(prvm_prog_t *prog)
2146 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2147 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2148 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2150 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2151 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2152 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2153 SV_FlushBroadcastMessages();
2156 static void VM_SV_te_explosion(prvm_prog_t *prog)
2158 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2159 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2160 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2162 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2163 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2164 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2165 SV_FlushBroadcastMessages();
2168 static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
2170 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2171 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2172 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2174 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2175 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2176 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2177 SV_FlushBroadcastMessages();
2180 static void VM_SV_te_wizspike(prvm_prog_t *prog)
2182 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2183 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2184 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2186 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2187 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2188 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2189 SV_FlushBroadcastMessages();
2192 static void VM_SV_te_knightspike(prvm_prog_t *prog)
2194 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2195 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2196 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2198 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2199 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2200 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2201 SV_FlushBroadcastMessages();
2204 static void VM_SV_te_lavasplash(prvm_prog_t *prog)
2206 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2207 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2208 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2210 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2211 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2212 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2213 SV_FlushBroadcastMessages();
2216 static void VM_SV_te_teleport(prvm_prog_t *prog)
2218 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2219 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2220 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2222 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2223 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2224 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2225 SV_FlushBroadcastMessages();
2228 static void VM_SV_te_explosion2(prvm_prog_t *prog)
2230 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2231 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2232 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2234 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2235 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2236 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2238 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2239 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2240 SV_FlushBroadcastMessages();
2243 static void VM_SV_te_lightning1(prvm_prog_t *prog)
2245 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2246 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2247 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2249 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2251 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2252 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2253 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2255 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2256 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2257 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2258 SV_FlushBroadcastMessages();
2261 static void VM_SV_te_lightning2(prvm_prog_t *prog)
2263 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2264 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2265 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2267 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2273 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2274 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2275 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2276 SV_FlushBroadcastMessages();
2279 static void VM_SV_te_lightning3(prvm_prog_t *prog)
2281 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2282 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2283 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2285 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2287 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2288 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2291 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2292 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2293 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2294 SV_FlushBroadcastMessages();
2297 static void VM_SV_te_beam(prvm_prog_t *prog)
2299 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2300 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2301 MSG_WriteByte(&sv.datagram, TE_BEAM);
2303 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2305 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2309 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2310 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2311 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2312 SV_FlushBroadcastMessages();
2315 static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
2317 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2318 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2319 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2320 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2321 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2322 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2323 SV_FlushBroadcastMessages();
2326 static void VM_SV_te_flamejet(prvm_prog_t *prog)
2328 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2329 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2330 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2332 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2334 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2336 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2337 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2338 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2340 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2341 SV_FlushBroadcastMessages();
2344 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2345 //this function originally written by KrimZon, made shorter by LadyHavoc
2346 static void VM_SV_clientcommand(prvm_prog_t *prog)
2348 client_t *temp_client;
2350 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2352 //find client for this entity
2353 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2354 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2356 Con_Print("PF_clientcommand: entity is not a client\n");
2360 temp_client = host_client;
2361 host_client = svs.clients + i;
2362 Cmd_ExecuteString(cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
2363 host_client = temp_client;
2366 //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)
2367 static void VM_SV_setattachment(prvm_prog_t *prog)
2369 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2370 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2371 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2374 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2376 if (e == prog->edicts)
2378 VM_Warning(prog, "setattachment: can not modify world entity\n");
2381 if (e->priv.server->free)
2383 VM_Warning(prog, "setattachment: can not modify free entity\n");
2387 if (tagentity == NULL)
2388 tagentity = prog->edicts;
2392 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2394 model = SV_GetModelFromEdict(tagentity);
2397 tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
2399 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);
2402 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));
2405 PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
2406 PRVM_serveredictfloat(e, tag_index) = tagindex;
2409 /////////////////////////////////////////
2410 // DP_MD3_TAGINFO extension coded by VorteX
2412 static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
2416 i = (int)PRVM_serveredictfloat(e, modelindex);
2417 if (i < 1 || i >= MAX_MODELS)
2420 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
2423 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2430 Matrix4x4_CreateIdentity(tag_localmatrix);
2432 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2434 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2445 void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix)
2448 float pitchsign = 1;
2450 scale = PRVM_serveredictfloat(ent, scale);
2455 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);
2458 pitchsign = SV_GetPitchSign(prog, ent);
2459 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);
2463 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2466 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2468 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2469 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2470 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2471 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2473 *out = identitymatrix;
2477 // Warnings/errors code:
2478 // 0 - normal (everything all-right)
2481 // 3 - null or non-precached model
2482 // 4 - no tags with requested index
2483 // 5 - runaway loop at attachment chain
2484 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2487 int modelindex, attachloop;
2488 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2491 *out = identitymatrix; // warnings and errors return identical matrix
2493 if (ent == prog->edicts)
2495 if (ent->priv.server->free)
2498 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
2499 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2502 model = SV_GetModelByIndex(modelindex);
2504 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2505 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2506 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2508 tagmatrix = identitymatrix;
2509 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2513 if (attachloop >= 256) // prevent runaway looping
2515 // apply transformation by child's tagindex on parent entity and then
2516 // by parent entity itself
2517 ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
2518 if (ret && attachloop == 0)
2520 SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
2521 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2522 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2523 // next iteration we process the parent entity
2524 if (PRVM_serveredictedict(ent, tag_entity))
2526 tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
2527 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
2534 // RENDER_VIEWMODEL magic
2535 if (PRVM_serveredictedict(ent, viewmodelforclient))
2537 Matrix4x4_Copy(&tagmatrix, out);
2538 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
2540 SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
2541 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2546 //float(entity ent, string tagname) gettagindex;
2548 static void VM_SV_gettagindex(prvm_prog_t *prog)
2551 const char *tag_name;
2554 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2556 ent = PRVM_G_EDICT(OFS_PARM0);
2557 tag_name = PRVM_G_STRING(OFS_PARM1);
2559 if (ent == prog->edicts)
2561 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2564 if (ent->priv.server->free)
2566 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2571 if (!SV_GetModelFromEdict(ent))
2572 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2575 tag_index = SV_GetTagIndex(prog, ent, tag_name);
2577 if(developer_extra.integer)
2578 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2580 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2583 //vector(entity ent, float tagindex) gettaginfo;
2584 static void VM_SV_gettaginfo(prvm_prog_t *prog)
2588 matrix4x4_t tag_matrix;
2589 matrix4x4_t tag_localmatrix;
2591 const char *tagname;
2593 vec3_t forward, left, up, origin;
2594 const model_t *model;
2596 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2598 e = PRVM_G_EDICT(OFS_PARM0);
2599 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2601 returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
2602 Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
2603 VectorCopy(forward, PRVM_serverglobalvector(v_forward));
2604 VectorNegate(left, PRVM_serverglobalvector(v_right));
2605 VectorCopy(up, PRVM_serverglobalvector(v_up));
2606 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
2607 model = SV_GetModelFromEdict(e);
2608 VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
2609 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
2610 VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
2611 SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2612 Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
2614 PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
2615 PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
2616 VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
2617 VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
2618 VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
2619 VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
2624 VM_Warning(prog, "gettagindex: can't affect world entity\n");
2627 VM_Warning(prog, "gettagindex: can't affect free entity\n");
2630 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2633 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2636 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2641 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2642 static void VM_SV_dropclient(prvm_prog_t *prog)
2645 client_t *oldhostclient;
2646 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2647 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2648 if (clientnum < 0 || clientnum >= svs.maxclients)
2650 VM_Warning(prog, "dropclient: not a client\n");
2653 if (!svs.clients[clientnum].active)
2655 VM_Warning(prog, "dropclient: that client slot is not connected\n");
2658 oldhostclient = host_client;
2659 host_client = svs.clients + clientnum;
2660 SV_DropClient(false);
2661 host_client = oldhostclient;
2664 //entity() spawnclient (DP_SV_BOTCLIENT)
2665 static void VM_SV_spawnclient(prvm_prog_t *prog)
2669 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2670 prog->xfunction->builtinsprofile += 2;
2672 for (i = 0;i < svs.maxclients;i++)
2674 if (!svs.clients[i].active)
2676 prog->xfunction->builtinsprofile += 100;
2677 SV_ConnectClient (i, NULL);
2678 // this has to be set or else ClientDisconnect won't be called
2679 // we assume the qc will call ClientConnect...
2680 svs.clients[i].clientconnectcalled = true;
2681 ed = PRVM_EDICT_NUM(i + 1);
2685 VM_RETURN_EDICT(ed);
2688 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2689 static void VM_SV_clienttype(prvm_prog_t *prog)
2692 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2693 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2694 if (clientnum < 0 || clientnum >= svs.maxclients)
2695 PRVM_G_FLOAT(OFS_RETURN) = 3;
2696 else if (!svs.clients[clientnum].active)
2697 PRVM_G_FLOAT(OFS_RETURN) = 0;
2698 else if (svs.clients[clientnum].netconnection)
2699 PRVM_G_FLOAT(OFS_RETURN) = 1;
2701 PRVM_G_FLOAT(OFS_RETURN) = 2;
2708 string(string key) serverkey
2711 static void VM_SV_serverkey(prvm_prog_t *prog)
2713 char string[VM_STRINGTEMP_LENGTH];
2714 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2715 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2716 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2719 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2720 static void VM_SV_setmodelindex(prvm_prog_t *prog)
2725 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2727 e = PRVM_G_EDICT(OFS_PARM0);
2728 if (e == prog->edicts)
2730 VM_Warning(prog, "setmodelindex: can not modify world entity\n");
2733 if (e->priv.server->free)
2735 VM_Warning(prog, "setmodelindex: can not modify free entity\n");
2738 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2739 if (i <= 0 || i >= MAX_MODELS)
2741 VM_Warning(prog, "setmodelindex: invalid modelindex\n");
2744 if (!sv.model_precache[i][0])
2746 VM_Warning(prog, "setmodelindex: model not precached\n");
2750 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2751 PRVM_serveredictfloat(e, modelindex) = i;
2753 mod = SV_GetModelByIndex(i);
2757 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2758 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
2760 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
2763 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
2766 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2767 static void VM_SV_modelnameforindex(prvm_prog_t *prog)
2770 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2772 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2774 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2775 if (i <= 0 || i >= MAX_MODELS)
2777 VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
2780 if (!sv.model_precache[i][0])
2782 VM_Warning(prog, "modelnameforindex: model not precached\n");
2786 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2789 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2790 static void VM_SV_particleeffectnum(prvm_prog_t *prog)
2793 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2794 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2797 PRVM_G_FLOAT(OFS_RETURN) = i;
2800 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2801 static void VM_SV_trailparticles(prvm_prog_t *prog)
2804 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2806 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2809 MSG_WriteByte(&sv.datagram, svc_trailparticles);
2810 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2811 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2812 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2813 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2814 MSG_WriteVector(&sv.datagram, start, sv.protocol);
2815 MSG_WriteVector(&sv.datagram, end, sv.protocol);
2816 SV_FlushBroadcastMessages();
2819 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
2820 static void VM_SV_pointparticles(prvm_prog_t *prog)
2822 int effectnum, count;
2824 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
2826 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2829 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2830 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
2831 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2832 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
2833 if (count == 1 && !VectorLength2(vel))
2836 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
2837 MSG_WriteShort(&sv.datagram, effectnum);
2838 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2842 // 1+2+12+12+2=29 bytes
2843 MSG_WriteByte(&sv.datagram, svc_pointparticles);
2844 MSG_WriteShort(&sv.datagram, effectnum);
2845 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2846 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
2847 MSG_WriteShort(&sv.datagram, count);
2850 SV_FlushBroadcastMessages();
2853 qbool SV_VM_ConsoleCommand (const char *text)
2855 prvm_prog_t *prog = SVVM_prog;
2856 int restorevm_tempstringsbuf_cursize;
2860 if(!sv.active || !prog || !prog->loaded)
2863 if (PRVM_serverfunction(ConsoleCmd))
2865 save_self = PRVM_serverglobaledict(self);
2866 PRVM_serverglobalfloat(time) = sv.time;
2867 restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
2868 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(sv.world.prog->edicts);
2869 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, text);
2870 prog->ExecuteProgram(prog, PRVM_serverfunction(ConsoleCmd), "QC function ConsoleCmd is missing");
2871 prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
2872 PRVM_serverglobaledict(self) = save_self;
2873 r = (int) PRVM_G_FLOAT(OFS_RETURN) != 0;
2878 // #352 void(string cmdname) registercommand (EXT_CSQC)
2879 static void VM_SV_registercommand (prvm_prog_t *prog)
2881 VM_SAFEPARMCOUNT(1, VM_SV_registercmd);
2882 if(!Cmd_Exists(cmd_server, PRVM_G_STRING(OFS_PARM0)))
2883 Cmd_AddCommand(CF_SERVER, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
2886 //PF_setpause, // void(float pause) setpause = #531;
2887 static void VM_SV_setpause(prvm_prog_t *prog) {
2889 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
2890 if (pauseValue != 0) { //pause the game
2892 sv.pausedstart = host.realtime;
2893 } else { //disable pause, in case it was enabled
2894 if (sv.paused != 0) {
2899 // send notification to all clients
2900 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
2901 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
2904 // #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.
2905 static void VM_SV_skel_create(prvm_prog_t *prog)
2907 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
2908 model_t *model = SV_GetModelByIndex(modelindex);
2909 skeleton_t *skeleton;
2911 PRVM_G_FLOAT(OFS_RETURN) = 0;
2912 if (!model || !model->num_bones)
2914 for (i = 0;i < MAX_EDICTS;i++)
2915 if (!prog->skeletons[i])
2917 if (i == MAX_EDICTS)
2919 prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
2920 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
2921 skeleton->model = model;
2922 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
2923 // initialize to identity matrices
2924 for (i = 0;i < skeleton->model->num_bones;i++)
2925 skeleton->relativetransforms[i] = identitymatrix;
2928 // #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
2929 static void VM_SV_skel_build(prvm_prog_t *prog)
2931 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2932 skeleton_t *skeleton;
2933 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
2934 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
2935 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
2936 int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
2937 int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
2938 model_t *model = SV_GetModelByIndex(modelindex);
2942 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
2943 frameblend_t frameblend[MAX_FRAMEBLENDS];
2944 matrix4x4_t bonematrix;
2946 PRVM_G_FLOAT(OFS_RETURN) = 0;
2947 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2949 firstbone = max(0, firstbone);
2950 lastbone = min(lastbone, model->num_bones - 1);
2951 lastbone = min(lastbone, skeleton->model->num_bones - 1);
2952 VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
2953 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
2954 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
2956 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
2958 memset(&bonematrix, 0, sizeof(bonematrix));
2959 for (blendindex = 0;blendindex < numblends;blendindex++)
2961 Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
2962 Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
2964 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
2965 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
2967 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
2970 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
2971 static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
2973 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2974 skeleton_t *skeleton;
2975 PRVM_G_FLOAT(OFS_RETURN) = 0;
2976 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2978 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
2981 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
2982 static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
2984 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2985 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2986 skeleton_t *skeleton;
2987 PRVM_G_INT(OFS_RETURN) = 0;
2988 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2990 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2992 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
2995 // #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)
2996 static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
2998 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2999 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3000 skeleton_t *skeleton;
3001 PRVM_G_FLOAT(OFS_RETURN) = 0;
3002 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3004 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3006 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3009 // #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
3010 static void VM_SV_skel_find_bone(prvm_prog_t *prog)
3012 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3013 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3014 skeleton_t *skeleton;
3015 PRVM_G_FLOAT(OFS_RETURN) = 0;
3016 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3018 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3021 // #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)
3022 static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
3024 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3025 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3026 skeleton_t *skeleton;
3028 vec3_t forward, left, up, origin;
3029 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3030 VectorClear(PRVM_clientglobalvector(v_forward));
3031 VectorClear(PRVM_clientglobalvector(v_right));
3032 VectorClear(PRVM_clientglobalvector(v_up));
3033 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3035 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3037 matrix = skeleton->relativetransforms[bonenum];
3038 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3039 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3040 VectorNegate(left, PRVM_clientglobalvector(v_right));
3041 VectorCopy(up, PRVM_clientglobalvector(v_up));
3042 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3045 // #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)
3046 static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
3048 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3049 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3050 skeleton_t *skeleton;
3053 vec3_t forward, left, up, origin;
3054 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3055 VectorClear(PRVM_clientglobalvector(v_forward));
3056 VectorClear(PRVM_clientglobalvector(v_right));
3057 VectorClear(PRVM_clientglobalvector(v_up));
3058 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3060 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3062 matrix = skeleton->relativetransforms[bonenum];
3063 // convert to absolute
3064 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3067 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3069 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3070 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3071 VectorNegate(left, PRVM_clientglobalvector(v_right));
3072 VectorCopy(up, PRVM_clientglobalvector(v_up));
3073 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3076 // #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)
3077 static void VM_SV_skel_set_bone(prvm_prog_t *prog)
3079 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3080 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3081 vec3_t forward, left, up, origin;
3082 skeleton_t *skeleton;
3084 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3086 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3088 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3089 VectorNegate(PRVM_clientglobalvector(v_right), left);
3090 VectorCopy(PRVM_clientglobalvector(v_up), up);
3091 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3092 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3093 skeleton->relativetransforms[bonenum] = matrix;
3096 // #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)
3097 static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
3099 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3100 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3101 vec3_t forward, left, up, origin;
3102 skeleton_t *skeleton;
3105 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3107 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3109 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3110 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3111 VectorNegate(PRVM_clientglobalvector(v_right), left);
3112 VectorCopy(PRVM_clientglobalvector(v_up), up);
3113 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3114 temp = skeleton->relativetransforms[bonenum];
3115 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3118 // #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)
3119 static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
3121 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3122 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3123 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3125 vec3_t forward, left, up, origin;
3126 skeleton_t *skeleton;
3129 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3131 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3132 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3133 VectorNegate(PRVM_clientglobalvector(v_right), left);
3134 VectorCopy(PRVM_clientglobalvector(v_up), up);
3135 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3136 firstbone = max(0, firstbone);
3137 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3138 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3140 temp = skeleton->relativetransforms[bonenum];
3141 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3145 // #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
3146 static void VM_SV_skel_copybones(prvm_prog_t *prog)
3148 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3149 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3150 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3151 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3153 skeleton_t *skeletondst;
3154 skeleton_t *skeletonsrc;
3155 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3157 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3159 firstbone = max(0, firstbone);
3160 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3161 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3162 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3163 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3166 // #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)
3167 static void VM_SV_skel_delete(prvm_prog_t *prog)
3169 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3170 skeleton_t *skeleton;
3171 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3174 prog->skeletons[skeletonindex] = NULL;
3177 // #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
3178 static void VM_SV_frameforname(prvm_prog_t *prog)
3180 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3181 model_t *model = SV_GetModelByIndex(modelindex);
3182 const char *name = PRVM_G_STRING(OFS_PARM1);
3184 PRVM_G_FLOAT(OFS_RETURN) = -1;
3185 if (!model || !model->animscenes)
3187 for (i = 0;i < model->numframes;i++)
3189 if (!strcasecmp(model->animscenes[i].name, name))
3191 PRVM_G_FLOAT(OFS_RETURN) = i;
3197 // #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.
3198 static void VM_SV_frameduration(prvm_prog_t *prog)
3200 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3201 model_t *model = SV_GetModelByIndex(modelindex);
3202 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3203 PRVM_G_FLOAT(OFS_RETURN) = 0;
3204 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3206 if (model->animscenes[framenum].framerate)
3207 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3211 prvm_builtin_t vm_sv_builtins[] = {
3212 NULL, // #0 NULL function (not callable) (QUAKE)
3213 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3214 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3215 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3216 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3217 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3218 VM_break, // #6 void() break (QUAKE)
3219 VM_random, // #7 float() random (QUAKE)
3220 VM_SV_sound, // #8 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
3221 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3222 VM_error, // #10 void(string e) error (QUAKE)
3223 VM_objerror, // #11 void(string e) objerror (QUAKE)
3224 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3225 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3226 VM_spawn, // #14 entity() spawn (QUAKE)
3227 VM_remove, // #15 void(entity e) remove (QUAKE)
3228 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3229 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3230 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3231 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3232 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3233 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3234 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3235 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3236 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3237 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3238 VM_ftos, // #26 string(float f) ftos (QUAKE)
3239 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3240 VM_coredump, // #28 void() coredump (QUAKE)
3241 VM_traceon, // #29 void() traceon (QUAKE)
3242 VM_traceoff, // #30 void() traceoff (QUAKE)
3243 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3244 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3245 NULL, // #33 (QUAKE)
3246 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3247 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3248 VM_rint, // #36 float(float v) rint (QUAKE)
3249 VM_floor, // #37 float(float v) floor (QUAKE)
3250 VM_ceil, // #38 float(float v) ceil (QUAKE)
3251 NULL, // #39 (QUAKE)
3252 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3253 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3254 NULL, // #42 (QUAKE)
3255 VM_fabs, // #43 float(float f) fabs (QUAKE)
3256 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3257 VM_cvar, // #45 float(string s) cvar (QUAKE)
3258 VM_localcmd_server, // #46 void(string s) localcmd (QUAKE)
3259 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3260 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3261 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3262 NULL, // #50 (QUAKE)
3263 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3264 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3265 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3266 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3267 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3268 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3269 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3270 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3271 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3272 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3273 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3274 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3275 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3276 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3277 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3278 NULL, // #66 (QUAKE)
3279 VM_SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3280 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3281 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3282 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3283 NULL, // #71 (QUAKE)
3284 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3285 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3286 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3287 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3288 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3289 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3290 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3291 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3292 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3293 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3294 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3295 NULL, // #83 (QUAKE)
3296 NULL, // #84 (QUAKE)
3297 NULL, // #85 (QUAKE)
3298 NULL, // #86 (QUAKE)
3299 NULL, // #87 (QUAKE)
3300 NULL, // #88 (QUAKE)
3301 NULL, // #89 (QUAKE)
3302 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3303 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3304 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3305 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3306 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3307 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3308 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3309 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3310 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3311 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3312 // FrikaC and Telejano range #100-#199
3323 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3324 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3325 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3326 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3327 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3328 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3329 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3330 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3331 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3332 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3413 // FTEQW range #200-#299
3432 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3435 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3436 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3437 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3438 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3439 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3440 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3441 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3442 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3443 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3444 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3446 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3454 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3477 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.
3478 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
3479 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3480 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3481 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)
3482 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
3483 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)
3484 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)
3485 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)
3486 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)
3487 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)
3488 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
3489 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)
3490 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
3491 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.
3514 // CSQC range #300-#399
3515 NULL, // #300 void() clearscene (EXT_CSQC)
3516 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3517 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3518 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3519 NULL, // #304 void() renderscene (EXT_CSQC)
3520 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3521 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3522 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3523 NULL, // #308 void() R_EndPolygon
3525 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3526 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3530 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3531 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3532 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3533 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3534 NULL, // #319 void(string name) freepic (EXT_CSQC)
3535 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3536 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3537 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3538 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3539 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3540 NULL, // #325 void(void) drawresetcliparea
3545 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3546 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3547 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3548 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3549 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3550 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3551 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3552 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3553 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3554 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3555 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3556 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3557 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3558 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3559 NULL, // #344 vector() getmousepos (EXT_CSQC)
3560 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3561 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3562 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3563 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3564 NULL, // #349 float() isdemo (EXT_CSQC)
3565 VM_isserver, // #350 float() isserver (EXT_CSQC)
3566 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3567 VM_SV_registercommand, // #352 void(string cmdname) registercommand (EXT_CSQC)
3568 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3569 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3575 NULL, // #360 float() readbyte (EXT_CSQC)
3576 NULL, // #361 float() readchar (EXT_CSQC)
3577 NULL, // #362 float() readshort (EXT_CSQC)
3578 NULL, // #363 float() readlong (EXT_CSQC)
3579 NULL, // #364 float() readcoord (EXT_CSQC)
3580 NULL, // #365 float() readangle (EXT_CSQC)
3581 NULL, // #366 string() readstring (EXT_CSQC)
3582 NULL, // #367 float() readfloat (EXT_CSQC)
3615 // LadyHavoc's range #400-#499
3616 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3617 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3618 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3619 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3620 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3621 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3622 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3623 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3624 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)
3625 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3626 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3627 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3628 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3629 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3630 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3631 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3632 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3633 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3634 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3635 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3636 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3637 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3638 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3639 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3640 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3641 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3642 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3643 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3644 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3645 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3646 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3647 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3648 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3649 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3650 VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3651 VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3652 VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3653 VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3654 VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3655 VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3656 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3657 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3658 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3659 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3660 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3661 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3662 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3663 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3664 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3665 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3666 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3667 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3668 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3669 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3670 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3671 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3672 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3673 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3675 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3676 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3677 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3678 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3679 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3680 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3681 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3682 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3683 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3684 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3685 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3687 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3688 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3689 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3690 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3691 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3692 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3693 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3694 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3695 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3696 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3697 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3698 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3699 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3700 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3701 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3702 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3710 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3711 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3712 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3713 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3714 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3715 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3716 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3717 VM_SV_WritePicture, // #501
3719 VM_whichpack, // #503 string(string) whichpack = #503;
3726 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3727 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3728 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3729 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)
3730 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3731 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3732 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3733 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3734 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3735 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3745 VM_loadfromdata, // #529
3746 VM_loadfromfile, // #530
3747 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3749 VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
3750 VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
3751 VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
3752 VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
3753 VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
3754 VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
3756 VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
3757 VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
3758 VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
3821 VM_callfunction, // #605
3822 VM_writetofile, // #606
3823 VM_isfunction, // #607
3829 VM_parseentitydata, // #613
3840 VM_SV_getextresponse, // #624 string getextresponse(void)
3843 VM_sprintf, // #627 string sprintf(string format, ...)
3844 VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
3845 VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
3855 VM_digest_hex, // #639
3858 VM_coverage, // #642
3862 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
3864 void SVVM_init_cmd(prvm_prog_t *prog)
3869 void SVVM_reset_cmd(prvm_prog_t *prog)
3871 World_End(&sv.world);
3873 if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
3875 func_t s = PRVM_serverfunction(SV_Shutdown);
3876 PRVM_serverglobalfloat(time) = sv.time;
3877 PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
3878 prog->ExecuteProgram(prog, s,"SV_Shutdown() required");