6 //============================================================================
11 const char *vm_sv_extensions[] = {
16 "DP_CON_ALIASPARAMETERS",
25 "DP_CSQC_ENTITYWORLDOBJECT",
26 "DP_CSQC_ENTITYMODELLIGHT",
27 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET",
29 "DP_CSQC_MINFPS_QUALITY",
30 "DP_CSQC_MULTIFRAME_INTERPOLATION",
31 "DP_CSQC_BOXPARTICLES",
32 "DP_CSQC_SPAWNPARTICLE",
33 "DP_CSQC_QUERYRENDERENTITY",
34 "DP_CSQC_ROTATEMOVES",
36 "DP_CSQC_V_CALCREFDEF_WIP1",
37 "DP_CSQC_V_CALCREFDEF_WIP2",
41 "DP_EF_DYNAMICMODELLIGHT",
50 "DP_EF_RESTARTANIM_BIT",
55 "DP_ENT_CUSTOMCOLORMAP",
56 "DP_ENT_EXTERIORMODELTOCLIENT",
59 "DP_ENT_LOWPRECISION",
61 "DP_ENT_TRAILEFFECTNUM",
63 "DP_GFX_EXTERNALTEXTURES",
64 "DP_GFX_EXTERNALTEXTURES_PERMAP",
66 "DP_GFX_MODEL_INTERPOLATION",
67 "DP_GFX_QUAKE3MODELTAGS",
71 "DP_GFX_FONTS_FREETYPE",
73 "DP_FONT_VARIABLEWIDTH",
75 "DP_HALFLIFE_MAP_CVAR",
78 "DP_LIGHTSTYLE_STATICVALUE",
82 "DP_MOVETYPEBOUNCEMISSILE",
83 "DP_MOVETYPEFLYWORLDONLY",
86 "DP_QC_ASINACOSATANATAN2TAN",
92 "DP_QC_CVAR_DEFSTRING",
93 "DP_QC_CVAR_DESCRIPTION",
97 "DP_QC_DIGEST_SHA256",
100 "DP_QC_ENTITYSTRING",
102 "DP_QC_EXTRESPONSEPACKET",
104 "DP_QC_FINDCHAINFLAGS",
105 "DP_QC_FINDCHAINFLOAT",
106 "DP_QC_FINDCHAIN_TOFIELD",
112 "DP_QC_GETSURFACETRIANGLE",
113 "DP_QC_GETSURFACEPOINTATTRIBUTE",
115 "DP_QC_GETTAGINFO_BONEPROPERTIES",
117 "DP_QC_GETTIME_CDTRACK",
121 "DP_QC_MULTIPLETEMPSTRINGS",
122 "DP_QC_NUM_FOR_EDICT",
124 "DP_QC_SINCOSSQRTPOW",
127 "DP_QC_STRINGBUFFERS",
128 "DP_QC_STRINGBUFFERS_CVARLIST",
129 "DP_QC_STRINGBUFFERS_EXT_WIP",
130 "DP_QC_STRINGCOLORFUNCTIONS",
131 "DP_QC_STRING_CASE_FUNCTIONS",
133 "DP_QC_TOKENIZEBYSEPARATOR",
134 "DP_QC_TOKENIZE_CONSOLE",
137 "DP_QC_TRACE_MOVETYPE_HITMODEL",
138 "DP_QC_TRACE_MOVETYPE_WORLDONLY",
139 "DP_QC_UNLIMITEDTEMPSTRINGS",
143 "DP_QC_VECTOANGLES_WITH_ROLL",
144 "DP_QC_VECTORVECTORS",
151 "DP_SKELETONOBJECTS",
152 "DP_SND_DIRECTIONLESSATTNNONE",
154 "DP_SND_SOUND7_WIP1",
155 "DP_SND_SOUND7_WIP2",
159 "DP_SND_GETSOUNDTIME",
161 "DP_VIDEO_SUBTITLES",
165 "DP_SV_BOUNCEFACTOR",
166 "DP_SV_CLIENTCAMERA",
167 "DP_SV_CLIENTCOLORS",
170 "DP_SV_CUSTOMIZEENTITYFORCLIENT",
171 "DP_SV_DISABLECLIENTPREDICTION",
172 "DP_SV_DISCARDABLEDEMO",
173 "DP_SV_DRAWONLYTOCLIENT",
176 "DP_SV_ENTITYCONTENTSTRANSITION",
177 "DP_SV_MODELFLAGS_AS_EFFECTS",
178 "DP_SV_MOVETYPESTEP_LANDEVENT",
180 "DP_SV_NODRAWTOCLIENT",
181 "DP_SV_ONENTITYNOSPAWNFUNCTION",
182 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION",
184 "DP_SV_PING_PACKETLOSS",
185 "DP_SV_PLAYERPHYSICS",
187 "DP_SV_POINTPARTICLES",
189 "DP_SV_PRECACHEANYTIME",
193 "DP_SV_ROTATINGBMODEL",
197 "DP_SV_SPAWNFUNC_PREFIX",
198 "DP_SV_WRITEPICTURE",
199 "DP_SV_WRITEUNTERMINATEDSTRING",
203 "DP_TE_EXPLOSIONRGB",
205 "DP_TE_PARTICLECUBE",
206 "DP_TE_PARTICLERAIN",
207 "DP_TE_PARTICLESNOW",
209 "DP_TE_QUADEFFECTS1",
212 "DP_TE_STANDARDEFFECTBUILTINS",
213 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO"
218 "FTE_CSQC_SKELETONOBJECTS",
221 "KRIMZON_SV_PARSECLIENTCOMMAND",
224 "NEXUIZ_PLAYERMODEL",
226 "PRYDON_CLIENTCURSOR",
227 "TENEBRAE_GFX_DLIGHTS",
232 //"EXT_CSQC" // not ready yet
239 This is the only valid way to move an object without using the physics of the world (setting velocity and waiting). Directly changing origin will not set internal links correctly, so clipping would be messed up. This should be called when an object is spawned, and then only if it is teleported.
241 setorigin (entity, origin)
244 static void VM_SV_setorigin(prvm_prog_t *prog)
248 VM_SAFEPARMCOUNT(2, VM_SV_setorigin);
250 e = PRVM_G_EDICT(OFS_PARM0);
251 if (e == prog->edicts)
253 VM_Warning(prog, "setorigin: can not modify world entity\n");
256 if (e->priv.server->free)
258 VM_Warning(prog, "setorigin: can not modify free entity\n");
261 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), PRVM_serveredictvector(e, origin));
262 if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
263 e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
267 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
268 static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max, qboolean rotate)
272 for (i=0 ; i<3 ; i++)
274 prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
276 // set derived values
277 VectorCopy (min, PRVM_serveredictvector(e, mins));
278 VectorCopy (max, PRVM_serveredictvector(e, maxs));
279 VectorSubtract (max, min, PRVM_serveredictvector(e, size));
288 the size box is rotated by the current angle
289 LadyHavoc: no it isn't...
291 setsize (entity, minvector, maxvector)
294 static void VM_SV_setsize(prvm_prog_t *prog)
299 VM_SAFEPARMCOUNT(3, VM_SV_setsize);
301 e = PRVM_G_EDICT(OFS_PARM0);
302 if (e == prog->edicts)
304 VM_Warning(prog, "setsize: can not modify world entity\n");
307 if (e->priv.server->free)
309 VM_Warning(prog, "setsize: can not modify free entity\n");
312 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
313 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
314 SetMinMaxSize(prog, e, mins, maxs, false);
322 setmodel(entity, model)
325 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
326 static void VM_SV_setmodel(prvm_prog_t *prog)
332 VM_SAFEPARMCOUNT(2, VM_SV_setmodel);
334 e = PRVM_G_EDICT(OFS_PARM0);
335 if (e == prog->edicts)
337 VM_Warning(prog, "setmodel: can not modify world entity\n");
340 if (e->priv.server->free)
342 VM_Warning(prog, "setmodel: can not modify free entity\n");
345 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
346 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
347 PRVM_serveredictfloat(e, modelindex) = i;
349 mod = SV_GetModelByIndex(i);
353 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
354 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
356 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
359 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
366 single print to a specific client
368 sprint(clientent, value)
371 static void VM_SV_sprint(prvm_prog_t *prog)
375 char string[VM_STRINGTEMP_LENGTH];
377 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
379 VM_VarString(prog, 1, string, sizeof(string));
381 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
382 // LadyHavoc: div0 requested that sprintto world operate like print
389 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
391 VM_Warning(prog, "tried to centerprint to a non-client\n");
395 client = svs.clients + entnum-1;
396 if (!client->netconnection)
399 MSG_WriteChar(&client->netconnection->message,svc_print);
400 MSG_WriteString(&client->netconnection->message, string);
408 single print to a specific client
410 centerprint(clientent, value)
413 static void VM_SV_centerprint(prvm_prog_t *prog)
417 char string[VM_STRINGTEMP_LENGTH];
419 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
421 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
423 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
425 VM_Warning(prog, "tried to centerprint to a non-client\n");
429 client = svs.clients + entnum-1;
430 if (!client->netconnection)
433 VM_VarString(prog, 1, string, sizeof(string));
434 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
435 MSG_WriteString(&client->netconnection->message, string);
442 particle(origin, color, count)
445 static void VM_SV_particle(prvm_prog_t *prog)
451 VM_SAFEPARMCOUNT(4, VM_SV_particle);
453 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
454 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
455 color = (int)PRVM_G_FLOAT(OFS_PARM2);
456 count = (int)PRVM_G_FLOAT(OFS_PARM3);
457 SV_StartParticle (org, dir, color, count);
467 static void VM_SV_ambientsound(prvm_prog_t *prog)
471 prvm_vec_t vol, attenuation;
474 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
476 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
477 samp = PRVM_G_STRING(OFS_PARM1);
478 vol = PRVM_G_FLOAT(OFS_PARM2);
479 attenuation = PRVM_G_FLOAT(OFS_PARM3);
481 // check to see if samp was properly precached
482 soundnum = SV_SoundIndex(samp, 1);
490 // add an svc_spawnambient command to the level signon packet
493 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
495 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
497 MSG_WriteVector(&sv.signon, pos, sv.protocol);
499 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
500 MSG_WriteShort (&sv.signon, soundnum);
502 MSG_WriteByte (&sv.signon, soundnum);
504 MSG_WriteByte (&sv.signon, (int)(vol*255));
505 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
513 Each entity can have eight independant sound sources, like voice,
516 Channel 0 is an auto-allocate channel, the others override anything
517 already running on that entity/channel pair.
519 An attenuation of 0 will play full volume everywhere in the level.
520 Larger attenuations will drop off.
524 static void VM_SV_sound(prvm_prog_t *prog)
528 prvm_edict_t *entity;
534 VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
536 entity = PRVM_G_EDICT(OFS_PARM0);
537 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
538 sample = PRVM_G_STRING(OFS_PARM2);
539 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
542 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
546 attenuation = PRVM_G_FLOAT(OFS_PARM4);
550 pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
555 if(channel >= 8 && channel <= 15) // weird QW feature
557 flags |= CHANNELFLAG_RELIABLE;
563 // LadyHavoc: we only let the qc set certain flags, others are off-limits
564 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
567 if (nvolume < 0 || nvolume > 255)
569 VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
573 if (attenuation < 0 || attenuation > 4)
575 VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
579 channel = CHAN_USER2ENGINE(channel);
581 if (!IS_CHAN(channel))
583 VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
587 SV_StartSound (entity, channel, sample, nvolume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange);
594 Follows the same logic as VM_SV_sound, except instead of
595 an entity, an origin for the sound is provided, and channel
596 is omitted (since no entity is being tracked).
600 static void VM_SV_pointsound(prvm_prog_t *prog)
608 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
610 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
611 sample = PRVM_G_STRING(OFS_PARM1);
612 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
613 attenuation = PRVM_G_FLOAT(OFS_PARM3);
614 pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
616 if (nvolume < 0 || nvolume > 255)
618 VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
622 if (attenuation < 0 || attenuation > 4)
624 VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
628 SV_StartPointSound (org, sample, nvolume, attenuation, pitchchange);
635 Used for use tracing and shot targeting
636 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
637 if the tryents flag is set.
639 traceline (vector1, vector2, movetype, ignore)
642 static void VM_SV_traceline(prvm_prog_t *prog)
649 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
651 prog->xfunction->builtinsprofile += 30;
653 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
654 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
655 move = (int)PRVM_G_FLOAT(OFS_PARM2);
656 ent = PRVM_G_EDICT(OFS_PARM3);
658 if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
659 prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
661 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value);
663 VM_SetTraceGlobals(prog, &trace);
671 Used for use tracing and shot targeting
672 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
673 if the tryents flag is set.
675 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
678 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
679 static void VM_SV_tracebox(prvm_prog_t *prog)
681 vec3_t v1, v2, m1, m2;
686 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
688 prog->xfunction->builtinsprofile += 30;
690 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
691 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
692 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
693 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
694 move = (int)PRVM_G_FLOAT(OFS_PARM4);
695 ent = PRVM_G_EDICT(OFS_PARM5);
697 if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
698 prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
700 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value);
702 VM_SetTraceGlobals(prog, &trace);
705 static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
709 vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
710 vec3_t original_origin;
711 vec3_t original_velocity;
712 vec3_t original_angles;
713 vec3_t original_avelocity;
716 VectorCopy(PRVM_serveredictvector(tossent, origin) , original_origin );
717 VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
718 VectorCopy(PRVM_serveredictvector(tossent, angles) , original_angles );
719 VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
721 gravity = PRVM_serveredictfloat(tossent, gravity);
724 gravity *= sv_gravity.value * 0.025;
726 for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
728 SV_CheckVelocity (tossent);
729 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
730 VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
731 VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
732 VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
733 VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
734 VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
735 VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
736 trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value);
737 VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
738 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
740 if (trace.fraction < 1)
744 VectorCopy(original_origin , PRVM_serveredictvector(tossent, origin) );
745 VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
746 VectorCopy(original_angles , PRVM_serveredictvector(tossent, angles) );
747 VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
752 static void VM_SV_tracetoss(prvm_prog_t *prog)
756 prvm_edict_t *ignore;
758 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
760 prog->xfunction->builtinsprofile += 600;
762 ent = PRVM_G_EDICT(OFS_PARM0);
763 if (ent == prog->edicts)
765 VM_Warning(prog, "tracetoss: can not use world entity\n");
768 ignore = PRVM_G_EDICT(OFS_PARM1);
770 trace = SV_Trace_Toss(prog, ent, ignore);
772 VM_SetTraceGlobals(prog, &trace);
775 //============================================================================
777 static int checkpvsbytes;
778 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
780 static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
786 // cycle to the next one
788 check = bound(1, check, svs.maxclients);
789 if (check == svs.maxclients)
797 prog->xfunction->builtinsprofile++;
799 if (i == svs.maxclients+1)
801 // look up the client's edict
802 ent = PRVM_EDICT_NUM(i);
803 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
804 if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
806 // found a valid client (possibly the same one again)
810 // get the PVS for the entity
811 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
813 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
814 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
823 Returns a client (or object that has a client enemy) that would be a
826 If there is more than one valid option, they are cycled each frame
828 If (self.origin + self.viewofs) is not in the PVS of the current target,
829 it is not returned at all.
834 int c_invis, c_notvis;
835 static void VM_SV_checkclient(prvm_prog_t *prog)
837 prvm_edict_t *ent, *self;
840 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
842 // find a new check if on a new frame
843 if (sv.time - sv.lastchecktime >= 0.1)
845 sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
846 sv.lastchecktime = sv.time;
849 // return check if it might be visible
850 ent = PRVM_EDICT_NUM(sv.lastcheck);
851 if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
853 VM_RETURN_EDICT(prog->edicts);
857 // if current entity can't possibly see the check entity, return 0
858 self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
859 VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
860 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
863 VM_RETURN_EDICT(prog->edicts);
867 // might be able to see it
869 VM_RETURN_EDICT(ent);
872 //============================================================================
878 Checks if an entity is in a point's PVS.
879 Should be fast but can be inexact.
881 float checkpvs(vector viewpos, entity viewee) = #240;
884 static void VM_SV_checkpvs(prvm_prog_t *prog)
886 vec3_t viewpos, absmin, absmax;
887 prvm_edict_t *viewee;
892 unsigned char fatpvs[MAX_MAP_LEAFS/8];
895 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
896 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
897 viewee = PRVM_G_EDICT(OFS_PARM1);
899 if(viewee->priv.server->free)
901 VM_Warning(prog, "checkpvs: can not check free entity\n");
902 PRVM_G_FLOAT(OFS_RETURN) = 4;
907 if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
909 // no PVS support on this worldmodel... darn
910 PRVM_G_FLOAT(OFS_RETURN) = 3;
913 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
916 // viewpos isn't in any PVS... darn
917 PRVM_G_FLOAT(OFS_RETURN) = 2;
920 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
921 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
922 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
924 // using fat PVS like FTEQW does (slow)
925 if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
927 // no PVS support on this worldmodel... darn
928 PRVM_G_FLOAT(OFS_RETURN) = 3;
931 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
934 // viewpos isn't in any PVS... darn
935 PRVM_G_FLOAT(OFS_RETURN) = 2;
938 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
939 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
940 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
949 Sends text over to the client's execution buffer
951 stuffcmd (clientent, value, ...)
954 static void VM_SV_stuffcmd(prvm_prog_t *prog)
958 char string[VM_STRINGTEMP_LENGTH];
960 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
962 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
963 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
965 VM_Warning(prog, "Can't stuffcmd to a non-client\n");
969 VM_VarString(prog, 1, string, sizeof(string));
972 host_client = svs.clients + entnum-1;
973 SV_ClientCommands ("%s", string);
981 Returns a chain of entities that have origins within a spherical area
983 findradius (origin, radius)
986 static void VM_SV_findradius(prvm_prog_t *prog)
988 prvm_edict_t *ent, *chain;
989 vec_t radius, radius2;
990 vec3_t org, eorg, mins, maxs;
993 static prvm_edict_t *touchedicts[MAX_EDICTS];
996 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
999 chainfield = PRVM_G_INT(OFS_PARM2);
1001 chainfield = prog->fieldoffsets.chain;
1003 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
1005 chain = (prvm_edict_t *)prog->edicts;
1007 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1008 radius = PRVM_G_FLOAT(OFS_PARM1);
1009 radius2 = radius * radius;
1011 mins[0] = org[0] - (radius + 1);
1012 mins[1] = org[1] - (radius + 1);
1013 mins[2] = org[2] - (radius + 1);
1014 maxs[0] = org[0] + (radius + 1);
1015 maxs[1] = org[1] + (radius + 1);
1016 maxs[2] = org[2] + (radius + 1);
1017 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1018 if (numtouchedicts > MAX_EDICTS)
1020 // this never happens
1021 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1022 numtouchedicts = MAX_EDICTS;
1024 for (i = 0;i < numtouchedicts;i++)
1026 ent = touchedicts[i];
1027 prog->xfunction->builtinsprofile++;
1028 // Quake did not return non-solid entities but darkplaces does
1029 // (note: this is the reason you can't blow up fallen zombies)
1030 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1032 // LadyHavoc: compare against bounding box rather than center so it
1033 // doesn't miss large objects, and use DotProduct instead of Length
1034 // for a major speedup
1035 VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
1036 if (sv_gameplayfix_findradiusdistancetobox.integer)
1038 eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
1039 eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
1040 eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
1043 VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
1044 if (DotProduct(eorg, eorg) < radius2)
1046 PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
1051 VM_RETURN_EDICT(chain);
1054 static void VM_SV_precache_sound(prvm_prog_t *prog)
1056 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1057 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1060 static void VM_SV_precache_model(prvm_prog_t *prog)
1062 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1063 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1064 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1071 float(float yaw, float dist[, settrace]) walkmove
1074 static void VM_SV_walkmove(prvm_prog_t *prog)
1083 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1085 // assume failure if it returns early
1086 PRVM_G_FLOAT(OFS_RETURN) = 0;
1088 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1089 if (ent == prog->edicts)
1091 VM_Warning(prog, "walkmove: can not modify world entity\n");
1094 if (ent->priv.server->free)
1096 VM_Warning(prog, "walkmove: can not modify free entity\n");
1099 yaw = PRVM_G_FLOAT(OFS_PARM0);
1100 dist = PRVM_G_FLOAT(OFS_PARM1);
1101 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1103 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1106 yaw = yaw*M_PI*2 / 360;
1108 move[0] = cos(yaw)*dist;
1109 move[1] = sin(yaw)*dist;
1112 // save program state, because SV_movestep may call other progs
1113 oldf = prog->xfunction;
1114 oldself = PRVM_serverglobaledict(self);
1116 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1119 // restore program state
1120 prog->xfunction = oldf;
1121 PRVM_serverglobaledict(self) = oldself;
1132 static void VM_SV_droptofloor(prvm_prog_t *prog)
1135 vec3_t end, entorigin, entmins, entmaxs;
1138 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1140 // assume failure if it returns early
1141 PRVM_G_FLOAT(OFS_RETURN) = 0;
1143 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1144 if (ent == prog->edicts)
1146 VM_Warning(prog, "droptofloor: can not modify world entity\n");
1149 if (ent->priv.server->free)
1151 VM_Warning(prog, "droptofloor: can not modify free entity\n");
1155 VectorCopy (PRVM_serveredictvector(ent, origin), end);
1158 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1159 SV_NudgeOutOfSolid(ent);
1161 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
1162 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
1163 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
1164 trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1165 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1168 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]);
1169 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
1170 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1171 VectorSubtract(trace.endpos, offset, trace.endpos);
1172 if (trace.startsolid)
1174 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]);
1176 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1177 PRVM_serveredictedict(ent, groundentity) = 0;
1178 PRVM_G_FLOAT(OFS_RETURN) = 1;
1180 else if (trace.fraction < 1)
1182 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]);
1183 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1184 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1185 SV_NudgeOutOfSolid(ent);
1187 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1188 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1189 PRVM_G_FLOAT(OFS_RETURN) = 1;
1190 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1191 ent->priv.server->suspendedinairflag = true;
1196 if (!trace.allsolid && trace.fraction < 1)
1198 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1200 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1201 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1202 PRVM_G_FLOAT(OFS_RETURN) = 1;
1203 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1204 ent->priv.server->suspendedinairflag = true;
1213 void(float style, string value) lightstyle
1216 static void VM_SV_lightstyle(prvm_prog_t *prog)
1223 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1225 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1226 val = PRVM_G_STRING(OFS_PARM1);
1228 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1229 prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
1232 // change the string in sv
1233 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1235 // send message to all clients on this server
1236 if (sv.state != ss_active)
1239 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1241 if (client->active && client->netconnection)
1243 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1244 MSG_WriteChar (&client->netconnection->message,style);
1245 MSG_WriteString (&client->netconnection->message, val);
1255 static void VM_SV_checkbottom(prvm_prog_t *prog)
1257 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1258 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1266 static void VM_SV_pointcontents(prvm_prog_t *prog)
1269 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1270 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
1271 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(point));
1278 Pick a vector for the player to shoot along
1279 vector aim(entity, missilespeed)
1282 static void VM_SV_aim(prvm_prog_t *prog)
1284 prvm_edict_t *ent, *check, *bestent;
1285 vec3_t start, dir, end, bestdir;
1288 float dist, bestdist;
1291 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1293 // assume failure if it returns early
1294 VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1295 // if sv_aim is so high it can't possibly accept anything, skip out early
1296 if (sv_aim.value >= 1)
1299 ent = PRVM_G_EDICT(OFS_PARM0);
1300 if (ent == prog->edicts)
1302 VM_Warning(prog, "aim: can not use world entity\n");
1305 if (ent->priv.server->free)
1307 VM_Warning(prog, "aim: can not use free entity\n");
1310 //speed = PRVM_G_FLOAT(OFS_PARM1);
1312 VectorCopy (PRVM_serveredictvector(ent, origin), start);
1315 // try sending a trace straight
1316 VectorCopy (PRVM_serverglobalvector(v_forward), dir);
1317 VectorMA (start, 2048, dir, end);
1318 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1319 if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
1320 && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
1322 VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1327 // try all possible entities
1328 VectorCopy (dir, bestdir);
1329 bestdist = sv_aim.value;
1332 check = PRVM_NEXT_EDICT(prog->edicts);
1333 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1335 prog->xfunction->builtinsprofile++;
1336 if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
1340 if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
1341 continue; // don't aim at teammate
1342 for (j=0 ; j<3 ; j++)
1343 end[j] = PRVM_serveredictvector(check, origin)[j]
1344 + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
1345 VectorSubtract (end, start, dir);
1346 VectorNormalize (dir);
1347 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1348 if (dist < bestdist)
1349 continue; // to far to turn
1350 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1351 if (tr.ent == check)
1352 { // can shoot at this one
1360 VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
1361 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1362 VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
1364 VectorNormalize (end);
1365 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1369 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1374 ===============================================================================
1378 ===============================================================================
1381 #define MSG_BROADCAST 0 // unreliable to all
1382 #define MSG_ONE 1 // reliable to one (msg_entity)
1383 #define MSG_ALL 2 // reliable to all
1384 #define MSG_INIT 3 // write to the init string
1385 #define MSG_ENTITY 5
1387 static sizebuf_t *WriteDest(prvm_prog_t *prog)
1393 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1397 return &sv.datagram;
1400 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
1401 entnum = PRVM_NUM_FOR_EDICT(ent);
1402 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1404 VM_Warning(prog, "WriteDest: tried to write to non-client\n");
1405 return &sv.reliable_datagram;
1408 return &svs.clients[entnum-1].netconnection->message;
1411 VM_Warning(prog, "WriteDest: bad destination\n");
1413 return &sv.reliable_datagram;
1419 return sv.writeentitiestoclient_msg;
1425 static void VM_SV_WriteByte(prvm_prog_t *prog)
1427 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1428 MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1431 static void VM_SV_WriteChar(prvm_prog_t *prog)
1433 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1434 MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1437 static void VM_SV_WriteShort(prvm_prog_t *prog)
1439 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1440 MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1443 static void VM_SV_WriteLong(prvm_prog_t *prog)
1445 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1446 MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1449 static void VM_SV_WriteAngle(prvm_prog_t *prog)
1451 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1452 MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1455 static void VM_SV_WriteCoord(prvm_prog_t *prog)
1457 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1458 MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1461 static void VM_SV_WriteString(prvm_prog_t *prog)
1463 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1464 MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1467 static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
1469 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1470 MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1474 static void VM_SV_WriteEntity(prvm_prog_t *prog)
1476 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1477 MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
1480 // writes a picture as at most size bytes of data
1482 // IMGNAME \0 SIZE(short) IMGDATA
1483 // if failed to read/compress:
1485 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1486 static void VM_SV_WritePicture(prvm_prog_t *prog)
1488 const char *imgname;
1492 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1494 imgname = PRVM_G_STRING(OFS_PARM1);
1495 size = (size_t) PRVM_G_FLOAT(OFS_PARM2);
1499 MSG_WriteString(WriteDest(prog), imgname);
1500 if(Image_Compress(imgname, size, &buf, &size))
1503 MSG_WriteShort(WriteDest(prog), (int)size);
1504 SZ_Write(WriteDest(prog), (unsigned char *) buf, (int)size);
1509 MSG_WriteShort(WriteDest(prog), 0);
1513 //////////////////////////////////////////////////////////
1515 static void VM_SV_makestatic(prvm_prog_t *prog)
1520 // allow 0 parameters due to an id1 qc bug in which this function is used
1521 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1522 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1524 if (prog->argc >= 1)
1525 ent = PRVM_G_EDICT(OFS_PARM0);
1527 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1528 if (ent == prog->edicts)
1530 VM_Warning(prog, "makestatic: can not modify world entity\n");
1533 if (ent->priv.server->free)
1535 VM_Warning(prog, "makestatic: can not modify free entity\n");
1540 if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
1545 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1546 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1547 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1549 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1551 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1552 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1553 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1557 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1558 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1559 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1562 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
1563 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
1564 for (i=0 ; i<3 ; i++)
1566 MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
1567 MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
1570 // throw the entity away now
1571 PRVM_ED_Free(prog, ent);
1574 //=============================================================================
1581 static void VM_SV_setspawnparms(prvm_prog_t *prog)
1587 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1589 ent = PRVM_G_EDICT(OFS_PARM0);
1590 i = PRVM_NUM_FOR_EDICT(ent);
1591 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1593 Con_Print("tried to setspawnparms on a non-client\n");
1597 // copy spawn parms out of the client_t
1598 client = svs.clients + i-1;
1599 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1600 (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
1607 Returns a color vector indicating the lighting at the requested point.
1609 (Internal Operation note: actually measures the light beneath the point, just like
1610 the model lighting on the client)
1615 static void VM_SV_getlight(prvm_prog_t *prog)
1617 vec3_t ambientcolor, diffusecolor, diffusenormal;
1619 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1620 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
1621 VectorClear(ambientcolor);
1622 VectorClear(diffusecolor);
1623 VectorClear(diffusenormal);
1624 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1625 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1626 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1631 unsigned char type; // 1/2/8 or 0 to indicate unused
1635 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)
1636 static int vm_customstats_last;
1638 void VM_CustomStats_Clear (void)
1640 memset(vm_customstats, 0, sizeof(vm_customstats));
1641 vm_customstats_last = -1;
1644 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1646 prvm_prog_t *prog = SVVM_prog;
1654 for(i=MIN_VM_STAT; i<=vm_customstats_last ;i++)
1656 if(!vm_customstats[i].type)
1658 switch(vm_customstats[i].type)
1660 //string as 16 bytes
1663 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1664 stats[i] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1665 stats[i+1] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1666 stats[i+2] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1667 stats[i+3] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1669 //float field sent as-is
1671 // 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
1672 u.f = PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1675 //integer value of float field
1677 stats[i] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1685 extern cvar_t sv_gameplayfix_customstats;
1687 // void(float index, float type, .void field) SV_AddStat = #232;
1688 // Set up an auto-sent player stat.
1689 // Client's get thier own fields sent to them. Index may not be less than 32.
1690 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1691 // 1: string (4 stats carrying a total of 16 charactures)
1692 // 2: float (one stat, float converted to an integer for transportation)
1693 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1694 static void VM_SV_AddStat(prvm_prog_t *prog)
1698 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1700 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1701 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1702 off = PRVM_G_INT (OFS_PARM2);
1711 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);
1717 VM_Warning(prog, "PF_SV_AddStat: index (%i) may not be less than %i\n", i, MIN_VM_STAT);
1721 if (i >= MAX_CL_STATS)
1723 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);
1727 if (i > (MAX_CL_STATS - 4) && type == 1)
1729 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);
1733 // these are hazardous to override but sort of allowed if one wants to be adventurous... and enjoys warnings.
1734 if (i < MIN_VM_STAT)
1735 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);
1736 else if (i >= MAX_VM_STAT && !sv_gameplayfix_customstats.integer)
1737 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);
1738 else if (i > (MAX_VM_STAT - 4) && type == 1 && !sv_gameplayfix_customstats.integer)
1739 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);
1741 vm_customstats[i].type = type;
1742 vm_customstats[i].fieldoffset = off;
1743 if(vm_customstats_last < i)
1744 vm_customstats_last = i;
1751 copies data from one entity to another
1753 copyentity(src, dst)
1756 static void VM_SV_copyentity(prvm_prog_t *prog)
1758 prvm_edict_t *in, *out;
1759 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1760 in = PRVM_G_EDICT(OFS_PARM0);
1761 if (in == prog->edicts)
1763 VM_Warning(prog, "copyentity: can not read world entity\n");
1766 if (in->priv.server->free)
1768 VM_Warning(prog, "copyentity: can not read free entity\n");
1771 out = PRVM_G_EDICT(OFS_PARM1);
1772 if (out == prog->edicts)
1774 VM_Warning(prog, "copyentity: can not modify world entity\n");
1777 if (out->priv.server->free)
1779 VM_Warning(prog, "copyentity: can not modify free entity\n");
1782 memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
1783 if (VectorCompare(PRVM_serveredictvector(out, absmin), PRVM_serveredictvector(out, absmax)))
1793 sets the color of a client and broadcasts the update to all connected clients
1795 setcolor(clientent, value)
1798 static void VM_SV_setcolor(prvm_prog_t *prog)
1803 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1804 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1805 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1807 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1809 Con_Print("tried to setcolor a non-client\n");
1813 client = svs.clients + entnum-1;
1816 PRVM_serveredictfloat(client->edict, clientcolors) = i;
1817 PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
1820 if (client->old_colors != client->colors)
1822 client->old_colors = client->colors;
1823 // send notification to all clients
1824 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1825 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1826 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1834 effect(origin, modelname, startframe, framecount, framerate)
1837 static void VM_SV_effect(prvm_prog_t *prog)
1842 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1843 s = PRVM_G_STRING(OFS_PARM1);
1846 VM_Warning(prog, "effect: no model specified\n");
1850 i = SV_ModelIndex(s, 1);
1853 VM_Warning(prog, "effect: model not precached\n");
1857 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1859 VM_Warning(prog, "effect: framecount < 1\n");
1863 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1865 VM_Warning(prog, "effect: framerate < 1\n");
1869 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1870 SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1873 static void VM_SV_te_blood(prvm_prog_t *prog)
1875 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1876 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1878 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1879 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1881 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1882 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1885 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1886 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1887 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1889 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1890 SV_FlushBroadcastMessages();
1893 static void VM_SV_te_bloodshower(prvm_prog_t *prog)
1895 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1896 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1898 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1899 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1901 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1902 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1903 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1905 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1906 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1909 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1911 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1912 SV_FlushBroadcastMessages();
1915 static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
1917 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1918 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1919 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1921 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1922 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1923 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1925 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1926 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1927 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1928 SV_FlushBroadcastMessages();
1931 static void VM_SV_te_particlecube(prvm_prog_t *prog)
1933 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1934 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1936 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1937 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1939 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1940 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1941 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1943 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1944 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1945 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1947 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1948 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1949 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1951 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1953 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1954 // gravity true/false
1955 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1957 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1958 SV_FlushBroadcastMessages();
1961 static void VM_SV_te_particlerain(prvm_prog_t *prog)
1963 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1964 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1966 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1967 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1969 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1970 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1971 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1973 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1974 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1977 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1978 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1979 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1981 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1983 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1984 SV_FlushBroadcastMessages();
1987 static void VM_SV_te_particlesnow(prvm_prog_t *prog)
1989 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1990 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1992 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1993 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1995 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1996 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1997 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1999 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2000 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2003 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2004 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2005 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2007 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2009 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2010 SV_FlushBroadcastMessages();
2013 static void VM_SV_te_spark(prvm_prog_t *prog)
2015 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
2016 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2018 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2019 MSG_WriteByte(&sv.datagram, TE_SPARK);
2021 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2022 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2023 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2025 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2026 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2027 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2029 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2030 SV_FlushBroadcastMessages();
2033 static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
2035 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
2036 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2037 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2039 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2040 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2041 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2042 SV_FlushBroadcastMessages();
2045 static void VM_SV_te_spikequad(prvm_prog_t *prog)
2047 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2048 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2049 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2051 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2052 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2053 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2054 SV_FlushBroadcastMessages();
2057 static void VM_SV_te_superspikequad(prvm_prog_t *prog)
2059 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2060 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2061 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2063 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2064 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2065 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2066 SV_FlushBroadcastMessages();
2069 static void VM_SV_te_explosionquad(prvm_prog_t *prog)
2071 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2072 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2073 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2075 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2076 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2077 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2078 SV_FlushBroadcastMessages();
2081 static void VM_SV_te_smallflash(prvm_prog_t *prog)
2083 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2084 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2085 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2087 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2088 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2089 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2090 SV_FlushBroadcastMessages();
2093 static void VM_SV_te_customflash(prvm_prog_t *prog)
2095 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2096 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2098 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2099 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2101 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2102 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2103 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2105 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2107 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2109 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2110 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2111 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2112 SV_FlushBroadcastMessages();
2115 static void VM_SV_te_gunshot(prvm_prog_t *prog)
2117 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2118 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2119 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2121 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2122 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2123 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2124 SV_FlushBroadcastMessages();
2127 static void VM_SV_te_spike(prvm_prog_t *prog)
2129 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2130 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2131 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2133 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2134 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2135 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2136 SV_FlushBroadcastMessages();
2139 static void VM_SV_te_superspike(prvm_prog_t *prog)
2141 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2142 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2143 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2145 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2146 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2147 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2148 SV_FlushBroadcastMessages();
2151 static void VM_SV_te_explosion(prvm_prog_t *prog)
2153 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2154 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2155 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2157 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2158 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2159 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2160 SV_FlushBroadcastMessages();
2163 static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
2165 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2166 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2167 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2169 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2170 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2171 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2172 SV_FlushBroadcastMessages();
2175 static void VM_SV_te_wizspike(prvm_prog_t *prog)
2177 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2178 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2179 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2181 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2182 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2184 SV_FlushBroadcastMessages();
2187 static void VM_SV_te_knightspike(prvm_prog_t *prog)
2189 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2190 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2191 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2193 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2194 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2195 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2196 SV_FlushBroadcastMessages();
2199 static void VM_SV_te_lavasplash(prvm_prog_t *prog)
2201 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2202 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2203 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2205 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2206 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2207 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2208 SV_FlushBroadcastMessages();
2211 static void VM_SV_te_teleport(prvm_prog_t *prog)
2213 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2214 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2215 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2217 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2218 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2220 SV_FlushBroadcastMessages();
2223 static void VM_SV_te_explosion2(prvm_prog_t *prog)
2225 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2226 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2227 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2229 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2230 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2231 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2233 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2234 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2235 SV_FlushBroadcastMessages();
2238 static void VM_SV_te_lightning1(prvm_prog_t *prog)
2240 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2241 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2242 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2244 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2246 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2247 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2248 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2250 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2251 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2252 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2253 SV_FlushBroadcastMessages();
2256 static void VM_SV_te_lightning2(prvm_prog_t *prog)
2258 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2259 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2260 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2262 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2264 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2265 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2266 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2268 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2271 SV_FlushBroadcastMessages();
2274 static void VM_SV_te_lightning3(prvm_prog_t *prog)
2276 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2277 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2280 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2282 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2283 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2284 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2287 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2288 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2289 SV_FlushBroadcastMessages();
2292 static void VM_SV_te_beam(prvm_prog_t *prog)
2294 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2295 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2296 MSG_WriteByte(&sv.datagram, TE_BEAM);
2298 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2300 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2301 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2302 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2305 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2307 SV_FlushBroadcastMessages();
2310 static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
2312 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2313 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2314 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2315 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2316 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2317 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2318 SV_FlushBroadcastMessages();
2321 static void VM_SV_te_flamejet(prvm_prog_t *prog)
2323 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2324 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2325 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2327 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2335 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2336 SV_FlushBroadcastMessages();
2339 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2340 //this function originally written by KrimZon, made shorter by LadyHavoc
2341 static void VM_SV_clientcommand(prvm_prog_t *prog)
2343 client_t *temp_client;
2345 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2347 //find client for this entity
2348 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2349 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2351 Con_Print("PF_clientcommand: entity is not a client\n");
2355 temp_client = host_client;
2356 host_client = svs.clients + i;
2357 Cmd_ExecuteString(&cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
2358 host_client = temp_client;
2361 //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)
2362 static void VM_SV_setattachment(prvm_prog_t *prog)
2364 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2365 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2366 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2369 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2371 if (e == prog->edicts)
2373 VM_Warning(prog, "setattachment: can not modify world entity\n");
2376 if (e->priv.server->free)
2378 VM_Warning(prog, "setattachment: can not modify free entity\n");
2382 if (tagentity == NULL)
2383 tagentity = prog->edicts;
2387 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2389 model = SV_GetModelFromEdict(tagentity);
2392 tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
2394 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);
2397 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));
2400 PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
2401 PRVM_serveredictfloat(e, tag_index) = tagindex;
2404 /////////////////////////////////////////
2405 // DP_MD3_TAGINFO extension coded by VorteX
2407 static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
2411 i = (int)PRVM_serveredictfloat(e, modelindex);
2412 if (i < 1 || i >= MAX_MODELS)
2415 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
2418 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2425 Matrix4x4_CreateIdentity(tag_localmatrix);
2427 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2429 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2440 void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2443 float pitchsign = 1;
2445 scale = PRVM_serveredictfloat(ent, scale);
2450 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);
2453 pitchsign = SV_GetPitchSign(prog, ent);
2454 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);
2458 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2461 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2463 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2464 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2465 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2466 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2468 *out = identitymatrix;
2472 // Warnings/errors code:
2473 // 0 - normal (everything all-right)
2476 // 3 - null or non-precached model
2477 // 4 - no tags with requested index
2478 // 5 - runaway loop at attachment chain
2479 extern cvar_t cl_bob;
2480 extern cvar_t cl_bobcycle;
2481 extern cvar_t cl_bobup;
2482 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2485 int modelindex, attachloop;
2486 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2489 *out = identitymatrix; // warnings and errors return identical matrix
2491 if (ent == prog->edicts)
2493 if (ent->priv.server->free)
2496 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
2497 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2500 model = SV_GetModelByIndex(modelindex);
2502 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2503 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2504 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2506 tagmatrix = identitymatrix;
2507 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2511 if (attachloop >= 256) // prevent runaway looping
2513 // apply transformation by child's tagindex on parent entity and then
2514 // by parent entity itself
2515 ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
2516 if (ret && attachloop == 0)
2518 SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
2519 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2520 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2521 // next iteration we process the parent entity
2522 if (PRVM_serveredictedict(ent, tag_entity))
2524 tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
2525 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
2532 // RENDER_VIEWMODEL magic
2533 if (PRVM_serveredictedict(ent, viewmodelforclient))
2535 Matrix4x4_Copy(&tagmatrix, out);
2536 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
2538 SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
2539 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2542 // Cl_bob, ported from rendering code
2543 if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
2546 // LadyHavoc: this code is *weird*, but not replacable (I think it
2547 // should be done in QC on the server, but oh well, quake is quake)
2548 // LadyHavoc: figured out bobup: the time at which the sin is at 180
2549 // degrees (which allows lengthening or squishing the peak or valley)
2550 cycle = sv.time/cl_bobcycle.value;
2551 cycle -= (int)cycle;
2552 if (cycle < cl_bobup.value)
2553 cycle = sin(M_PI * cycle / cl_bobup.value);
2555 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2556 // bob is proportional to velocity in the xy plane
2557 // (don't count Z, or jumping messes it up)
2558 bob = sqrt(PRVM_serveredictvector(ent, velocity)[0]*PRVM_serveredictvector(ent, velocity)[0] + PRVM_serveredictvector(ent, velocity)[1]*PRVM_serveredictvector(ent, velocity)[1])*cl_bob.value;
2559 bob = bob*0.3 + bob*0.7*cycle;
2560 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2567 //float(entity ent, string tagname) gettagindex;
2569 static void VM_SV_gettagindex(prvm_prog_t *prog)
2572 const char *tag_name;
2575 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2577 ent = PRVM_G_EDICT(OFS_PARM0);
2578 tag_name = PRVM_G_STRING(OFS_PARM1);
2580 if (ent == prog->edicts)
2582 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2585 if (ent->priv.server->free)
2587 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2592 if (!SV_GetModelFromEdict(ent))
2593 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2596 tag_index = SV_GetTagIndex(prog, ent, tag_name);
2598 if(developer_extra.integer)
2599 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2601 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2604 //vector(entity ent, float tagindex) gettaginfo;
2605 static void VM_SV_gettaginfo(prvm_prog_t *prog)
2609 matrix4x4_t tag_matrix;
2610 matrix4x4_t tag_localmatrix;
2612 const char *tagname;
2614 vec3_t forward, left, up, origin;
2615 const dp_model_t *model;
2617 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2619 e = PRVM_G_EDICT(OFS_PARM0);
2620 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2622 returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
2623 Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
2624 VectorCopy(forward, PRVM_serverglobalvector(v_forward));
2625 VectorNegate(left, PRVM_serverglobalvector(v_right));
2626 VectorCopy(up, PRVM_serverglobalvector(v_up));
2627 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
2628 model = SV_GetModelFromEdict(e);
2629 VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
2630 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
2631 VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
2632 SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2633 Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
2635 PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
2636 PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
2637 VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
2638 VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
2639 VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
2640 VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
2645 VM_Warning(prog, "gettagindex: can't affect world entity\n");
2648 VM_Warning(prog, "gettagindex: can't affect free entity\n");
2651 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2654 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2657 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2662 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2663 static void VM_SV_dropclient(prvm_prog_t *prog)
2666 client_t *oldhostclient;
2667 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2668 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2669 if (clientnum < 0 || clientnum >= svs.maxclients)
2671 VM_Warning(prog, "dropclient: not a client\n");
2674 if (!svs.clients[clientnum].active)
2676 VM_Warning(prog, "dropclient: that client slot is not connected\n");
2679 oldhostclient = host_client;
2680 host_client = svs.clients + clientnum;
2681 SV_DropClient(false);
2682 host_client = oldhostclient;
2685 //entity() spawnclient (DP_SV_BOTCLIENT)
2686 static void VM_SV_spawnclient(prvm_prog_t *prog)
2690 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2691 prog->xfunction->builtinsprofile += 2;
2693 for (i = 0;i < svs.maxclients;i++)
2695 if (!svs.clients[i].active)
2697 prog->xfunction->builtinsprofile += 100;
2698 SV_ConnectClient (i, NULL);
2699 // this has to be set or else ClientDisconnect won't be called
2700 // we assume the qc will call ClientConnect...
2701 svs.clients[i].clientconnectcalled = true;
2702 ed = PRVM_EDICT_NUM(i + 1);
2706 VM_RETURN_EDICT(ed);
2709 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2710 static void VM_SV_clienttype(prvm_prog_t *prog)
2713 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2714 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2715 if (clientnum < 0 || clientnum >= svs.maxclients)
2716 PRVM_G_FLOAT(OFS_RETURN) = 3;
2717 else if (!svs.clients[clientnum].active)
2718 PRVM_G_FLOAT(OFS_RETURN) = 0;
2719 else if (svs.clients[clientnum].netconnection)
2720 PRVM_G_FLOAT(OFS_RETURN) = 1;
2722 PRVM_G_FLOAT(OFS_RETURN) = 2;
2729 string(string key) serverkey
2732 static void VM_SV_serverkey(prvm_prog_t *prog)
2734 char string[VM_STRINGTEMP_LENGTH];
2735 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2736 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2737 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2740 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2741 static void VM_SV_setmodelindex(prvm_prog_t *prog)
2746 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2748 e = PRVM_G_EDICT(OFS_PARM0);
2749 if (e == prog->edicts)
2751 VM_Warning(prog, "setmodelindex: can not modify world entity\n");
2754 if (e->priv.server->free)
2756 VM_Warning(prog, "setmodelindex: can not modify free entity\n");
2759 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2760 if (i <= 0 || i >= MAX_MODELS)
2762 VM_Warning(prog, "setmodelindex: invalid modelindex\n");
2765 if (!sv.model_precache[i][0])
2767 VM_Warning(prog, "setmodelindex: model not precached\n");
2771 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2772 PRVM_serveredictfloat(e, modelindex) = i;
2774 mod = SV_GetModelByIndex(i);
2778 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2779 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
2781 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
2784 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
2787 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2788 static void VM_SV_modelnameforindex(prvm_prog_t *prog)
2791 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2793 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2795 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2796 if (i <= 0 || i >= MAX_MODELS)
2798 VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
2801 if (!sv.model_precache[i][0])
2803 VM_Warning(prog, "modelnameforindex: model not precached\n");
2807 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2810 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2811 static void VM_SV_particleeffectnum(prvm_prog_t *prog)
2814 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2815 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2818 PRVM_G_FLOAT(OFS_RETURN) = i;
2821 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2822 static void VM_SV_trailparticles(prvm_prog_t *prog)
2825 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2827 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2830 MSG_WriteByte(&sv.datagram, svc_trailparticles);
2831 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2832 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2833 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2834 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2835 MSG_WriteVector(&sv.datagram, start, sv.protocol);
2836 MSG_WriteVector(&sv.datagram, end, sv.protocol);
2837 SV_FlushBroadcastMessages();
2840 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
2841 static void VM_SV_pointparticles(prvm_prog_t *prog)
2843 int effectnum, count;
2845 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
2847 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2850 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2851 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
2852 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2853 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
2854 if (count == 1 && !VectorLength2(vel))
2857 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
2858 MSG_WriteShort(&sv.datagram, effectnum);
2859 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2863 // 1+2+12+12+2=29 bytes
2864 MSG_WriteByte(&sv.datagram, svc_pointparticles);
2865 MSG_WriteShort(&sv.datagram, effectnum);
2866 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2867 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
2868 MSG_WriteShort(&sv.datagram, count);
2871 SV_FlushBroadcastMessages();
2874 //PF_setpause, // void(float pause) setpause = #531;
2875 static void VM_SV_setpause(prvm_prog_t *prog) {
2877 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
2878 if (pauseValue != 0) { //pause the game
2880 sv.pausedstart = host.realtime;
2881 } else { //disable pause, in case it was enabled
2882 if (sv.paused != 0) {
2887 // send notification to all clients
2888 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
2889 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
2892 // #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.
2893 static void VM_SV_skel_create(prvm_prog_t *prog)
2895 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
2896 dp_model_t *model = SV_GetModelByIndex(modelindex);
2897 skeleton_t *skeleton;
2899 PRVM_G_FLOAT(OFS_RETURN) = 0;
2900 if (!model || !model->num_bones)
2902 for (i = 0;i < MAX_EDICTS;i++)
2903 if (!prog->skeletons[i])
2905 if (i == MAX_EDICTS)
2907 prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
2908 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
2909 skeleton->model = model;
2910 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
2911 // initialize to identity matrices
2912 for (i = 0;i < skeleton->model->num_bones;i++)
2913 skeleton->relativetransforms[i] = identitymatrix;
2916 // #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
2917 static void VM_SV_skel_build(prvm_prog_t *prog)
2919 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2920 skeleton_t *skeleton;
2921 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
2922 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
2923 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
2924 int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
2925 int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
2926 dp_model_t *model = SV_GetModelByIndex(modelindex);
2930 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
2931 frameblend_t frameblend[MAX_FRAMEBLENDS];
2932 matrix4x4_t bonematrix;
2934 PRVM_G_FLOAT(OFS_RETURN) = 0;
2935 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2937 firstbone = max(0, firstbone);
2938 lastbone = min(lastbone, model->num_bones - 1);
2939 lastbone = min(lastbone, skeleton->model->num_bones - 1);
2940 VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
2941 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
2942 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
2944 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
2946 memset(&bonematrix, 0, sizeof(bonematrix));
2947 for (blendindex = 0;blendindex < numblends;blendindex++)
2949 Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
2950 Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
2952 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
2953 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
2955 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
2958 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
2959 static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
2961 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2962 skeleton_t *skeleton;
2963 PRVM_G_FLOAT(OFS_RETURN) = 0;
2964 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2966 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
2969 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
2970 static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
2972 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2973 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2974 skeleton_t *skeleton;
2975 PRVM_G_INT(OFS_RETURN) = 0;
2976 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2978 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2980 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
2983 // #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)
2984 static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
2986 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2987 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2988 skeleton_t *skeleton;
2989 PRVM_G_FLOAT(OFS_RETURN) = 0;
2990 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2992 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2994 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
2997 // #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
2998 static void VM_SV_skel_find_bone(prvm_prog_t *prog)
3000 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3001 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3002 skeleton_t *skeleton;
3003 PRVM_G_FLOAT(OFS_RETURN) = 0;
3004 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3006 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3009 // #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)
3010 static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
3012 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3013 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3014 skeleton_t *skeleton;
3016 vec3_t forward, left, up, origin;
3017 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3018 VectorClear(PRVM_clientglobalvector(v_forward));
3019 VectorClear(PRVM_clientglobalvector(v_right));
3020 VectorClear(PRVM_clientglobalvector(v_up));
3021 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3023 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3025 matrix = skeleton->relativetransforms[bonenum];
3026 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3027 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3028 VectorNegate(left, PRVM_clientglobalvector(v_right));
3029 VectorCopy(up, PRVM_clientglobalvector(v_up));
3030 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3033 // #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)
3034 static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
3036 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3037 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3038 skeleton_t *skeleton;
3041 vec3_t forward, left, up, origin;
3042 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3043 VectorClear(PRVM_clientglobalvector(v_forward));
3044 VectorClear(PRVM_clientglobalvector(v_right));
3045 VectorClear(PRVM_clientglobalvector(v_up));
3046 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3048 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3050 matrix = skeleton->relativetransforms[bonenum];
3051 // convert to absolute
3052 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3055 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3057 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3058 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3059 VectorNegate(left, PRVM_clientglobalvector(v_right));
3060 VectorCopy(up, PRVM_clientglobalvector(v_up));
3061 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3064 // #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)
3065 static void VM_SV_skel_set_bone(prvm_prog_t *prog)
3067 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3068 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3069 vec3_t forward, left, up, origin;
3070 skeleton_t *skeleton;
3072 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3074 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3076 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3077 VectorNegate(PRVM_clientglobalvector(v_right), left);
3078 VectorCopy(PRVM_clientglobalvector(v_up), up);
3079 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3080 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3081 skeleton->relativetransforms[bonenum] = matrix;
3084 // #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)
3085 static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
3087 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3088 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3089 vec3_t forward, left, up, origin;
3090 skeleton_t *skeleton;
3093 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3095 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3097 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3098 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3099 VectorNegate(PRVM_clientglobalvector(v_right), left);
3100 VectorCopy(PRVM_clientglobalvector(v_up), up);
3101 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3102 temp = skeleton->relativetransforms[bonenum];
3103 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3106 // #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)
3107 static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
3109 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3110 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3111 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3113 vec3_t forward, left, up, origin;
3114 skeleton_t *skeleton;
3117 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3119 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3120 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3121 VectorNegate(PRVM_clientglobalvector(v_right), left);
3122 VectorCopy(PRVM_clientglobalvector(v_up), up);
3123 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3124 firstbone = max(0, firstbone);
3125 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3126 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3128 temp = skeleton->relativetransforms[bonenum];
3129 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3133 // #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
3134 static void VM_SV_skel_copybones(prvm_prog_t *prog)
3136 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3137 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3138 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3139 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3141 skeleton_t *skeletondst;
3142 skeleton_t *skeletonsrc;
3143 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3145 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3147 firstbone = max(0, firstbone);
3148 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3149 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3150 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3151 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3154 // #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)
3155 static void VM_SV_skel_delete(prvm_prog_t *prog)
3157 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3158 skeleton_t *skeleton;
3159 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3162 prog->skeletons[skeletonindex] = NULL;
3165 // #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
3166 static void VM_SV_frameforname(prvm_prog_t *prog)
3168 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3169 dp_model_t *model = SV_GetModelByIndex(modelindex);
3170 const char *name = PRVM_G_STRING(OFS_PARM1);
3172 PRVM_G_FLOAT(OFS_RETURN) = -1;
3173 if (!model || !model->animscenes)
3175 for (i = 0;i < model->numframes;i++)
3177 if (!strcasecmp(model->animscenes[i].name, name))
3179 PRVM_G_FLOAT(OFS_RETURN) = i;
3185 // #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.
3186 static void VM_SV_frameduration(prvm_prog_t *prog)
3188 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3189 dp_model_t *model = SV_GetModelByIndex(modelindex);
3190 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3191 PRVM_G_FLOAT(OFS_RETURN) = 0;
3192 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3194 if (model->animscenes[framenum].framerate)
3195 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3199 prvm_builtin_t vm_sv_builtins[] = {
3200 NULL, // #0 NULL function (not callable) (QUAKE)
3201 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3202 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3203 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3204 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3205 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3206 VM_break, // #6 void() break (QUAKE)
3207 VM_random, // #7 float() random (QUAKE)
3208 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3209 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3210 VM_error, // #10 void(string e) error (QUAKE)
3211 VM_objerror, // #11 void(string e) objerror (QUAKE)
3212 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3213 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3214 VM_spawn, // #14 entity() spawn (QUAKE)
3215 VM_remove, // #15 void(entity e) remove (QUAKE)
3216 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3217 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3218 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3219 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3220 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3221 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3222 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3223 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3224 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3225 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3226 VM_ftos, // #26 string(float f) ftos (QUAKE)
3227 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3228 VM_coredump, // #28 void() coredump (QUAKE)
3229 VM_traceon, // #29 void() traceon (QUAKE)
3230 VM_traceoff, // #30 void() traceoff (QUAKE)
3231 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3232 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3233 NULL, // #33 (QUAKE)
3234 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3235 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3236 VM_rint, // #36 float(float v) rint (QUAKE)
3237 VM_floor, // #37 float(float v) floor (QUAKE)
3238 VM_ceil, // #38 float(float v) ceil (QUAKE)
3239 NULL, // #39 (QUAKE)
3240 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3241 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3242 NULL, // #42 (QUAKE)
3243 VM_fabs, // #43 float(float f) fabs (QUAKE)
3244 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3245 VM_cvar, // #45 float(string s) cvar (QUAKE)
3246 VM_localcmd_server, // #46 void(string s) localcmd (QUAKE)
3247 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3248 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3249 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3250 NULL, // #50 (QUAKE)
3251 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3252 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3253 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3254 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3255 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3256 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3257 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3258 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3259 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3260 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3261 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3262 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3263 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3264 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3265 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3266 NULL, // #66 (QUAKE)
3267 VM_SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3268 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3269 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3270 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3271 NULL, // #71 (QUAKE)
3272 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3273 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3274 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3275 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3276 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3277 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3278 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3279 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3280 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3281 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3282 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3283 NULL, // #83 (QUAKE)
3284 NULL, // #84 (QUAKE)
3285 NULL, // #85 (QUAKE)
3286 NULL, // #86 (QUAKE)
3287 NULL, // #87 (QUAKE)
3288 NULL, // #88 (QUAKE)
3289 NULL, // #89 (QUAKE)
3290 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3291 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3292 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3293 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3294 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3295 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3296 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3297 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3298 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3299 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3300 // FrikaC and Telejano range #100-#199
3311 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3312 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3313 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3314 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3315 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3316 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3317 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3318 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3319 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3320 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3401 // FTEQW range #200-#299
3420 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3423 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3424 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3425 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3426 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3427 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3428 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3429 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3430 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3431 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3432 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3434 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3442 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3465 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.
3466 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
3467 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3468 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3469 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)
3470 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
3471 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)
3472 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)
3473 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)
3474 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)
3475 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)
3476 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
3477 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)
3478 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
3479 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.
3502 // CSQC range #300-#399
3503 NULL, // #300 void() clearscene (EXT_CSQC)
3504 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3505 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3506 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3507 NULL, // #304 void() renderscene (EXT_CSQC)
3508 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3509 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3510 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3511 NULL, // #308 void() R_EndPolygon
3513 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3514 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3518 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3519 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3520 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3521 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3522 NULL, // #319 void(string name) freepic (EXT_CSQC)
3523 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3524 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3525 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3526 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3527 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3528 NULL, // #325 void(void) drawresetcliparea
3533 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3534 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3535 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3536 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3537 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3538 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3539 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3540 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3541 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3542 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3543 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3544 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3545 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3546 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3547 NULL, // #344 vector() getmousepos (EXT_CSQC)
3548 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3549 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3550 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3551 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3552 NULL, // #349 float() isdemo (EXT_CSQC)
3553 VM_isserver, // #350 float() isserver (EXT_CSQC)
3554 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3555 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3556 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3557 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3563 NULL, // #360 float() readbyte (EXT_CSQC)
3564 NULL, // #361 float() readchar (EXT_CSQC)
3565 NULL, // #362 float() readshort (EXT_CSQC)
3566 NULL, // #363 float() readlong (EXT_CSQC)
3567 NULL, // #364 float() readcoord (EXT_CSQC)
3568 NULL, // #365 float() readangle (EXT_CSQC)
3569 NULL, // #366 string() readstring (EXT_CSQC)
3570 NULL, // #367 float() readfloat (EXT_CSQC)
3603 // LadyHavoc's range #400-#499
3604 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3605 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3606 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3607 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3608 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3609 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3610 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3611 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3612 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)
3613 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3614 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3615 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3616 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3617 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3618 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3619 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3620 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3621 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3622 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3623 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3624 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3625 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3626 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3627 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3628 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3629 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3630 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3631 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3632 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3633 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3634 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3635 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3636 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3637 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3638 VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3639 VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3640 VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3641 VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3642 VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3643 VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3644 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3645 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3646 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3647 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3648 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3649 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3650 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3651 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3652 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3653 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3654 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3655 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3656 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3657 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3658 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3659 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3660 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3661 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3663 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3664 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3665 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3666 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3667 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3668 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3669 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3670 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3671 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3672 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3673 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3675 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3676 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3677 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3678 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3679 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3680 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3681 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3682 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3683 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3684 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3685 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3686 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3687 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3688 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3689 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3690 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3698 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3699 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3700 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3701 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3702 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3703 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3704 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3705 VM_SV_WritePicture, // #501
3707 VM_whichpack, // #503 string(string) whichpack = #503;
3714 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3715 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3716 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3717 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)
3718 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3719 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3720 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3721 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3722 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3723 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3733 VM_loadfromdata, // #529
3734 VM_loadfromfile, // #530
3735 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3737 VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
3738 VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
3739 VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
3740 VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
3741 VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
3742 VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
3744 VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
3745 VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
3746 VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
3809 VM_callfunction, // #605
3810 VM_writetofile, // #606
3811 VM_isfunction, // #607
3817 VM_parseentitydata, // #613
3828 VM_SV_getextresponse, // #624 string getextresponse(void)
3831 VM_sprintf, // #627 string sprintf(string format, ...)
3832 VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
3833 VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
3843 VM_digest_hex, // #639
3846 VM_coverage, // #642
3850 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
3852 void SVVM_init_cmd(prvm_prog_t *prog)
3857 void SVVM_reset_cmd(prvm_prog_t *prog)
3859 World_End(&sv.world);
3861 if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
3863 func_t s = PRVM_serverfunction(SV_Shutdown);
3864 PRVM_serverglobalfloat(time) = sv.time;
3865 PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
3866 prog->ExecuteProgram(prog, s,"SV_Shutdown() required");