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.
522 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
525 static void VM_SV_sound(prvm_prog_t *prog)
529 prvm_edict_t *entity;
535 VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
537 entity = PRVM_G_EDICT(OFS_PARM0);
538 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
539 sample = PRVM_G_STRING(OFS_PARM2);
540 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
543 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
547 attenuation = PRVM_G_FLOAT(OFS_PARM4);
551 pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
556 if(channel >= 8 && channel <= 15) // weird QW feature
558 flags |= CHANNELFLAG_RELIABLE;
564 // LadyHavoc: we only let the qc set certain flags, others are off-limits
565 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
568 if (nvolume < 0 || nvolume > 255)
570 VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
574 if (attenuation < 0 || attenuation > 4)
576 VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
580 channel = CHAN_USER2ENGINE(channel);
582 if (!IS_CHAN(channel))
584 VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
588 SV_StartSound (entity, channel, sample, nvolume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange);
595 Follows the same logic as VM_SV_sound, except instead of
596 an entity, an origin for the sound is provided, and channel
597 is omitted (since no entity is being tracked).
601 static void VM_SV_pointsound(prvm_prog_t *prog)
609 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
611 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
612 sample = PRVM_G_STRING(OFS_PARM1);
613 nvolume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
614 attenuation = PRVM_G_FLOAT(OFS_PARM3);
615 pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
617 if (nvolume < 0 || nvolume > 255)
619 VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
623 if (attenuation < 0 || attenuation > 4)
625 VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
629 SV_StartPointSound (org, sample, nvolume, attenuation, pitchchange);
636 Used for use tracing and shot targeting
637 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
638 if the tryents flag is set.
640 traceline (vector1, vector2, movetype, ignore)
643 static void VM_SV_traceline(prvm_prog_t *prog)
650 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
652 prog->xfunction->builtinsprofile += 30;
654 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
655 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
656 move = (int)PRVM_G_FLOAT(OFS_PARM2);
657 ent = PRVM_G_EDICT(OFS_PARM3);
659 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]))
660 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));
662 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value);
664 VM_SetTraceGlobals(prog, &trace);
672 Used for use tracing and shot targeting
673 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
674 if the tryents flag is set.
676 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
679 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
680 static void VM_SV_tracebox(prvm_prog_t *prog)
682 vec3_t v1, v2, m1, m2;
687 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
689 prog->xfunction->builtinsprofile += 30;
691 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
692 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
693 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
694 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
695 move = (int)PRVM_G_FLOAT(OFS_PARM4);
696 ent = PRVM_G_EDICT(OFS_PARM5);
698 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]))
699 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));
701 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value);
703 VM_SetTraceGlobals(prog, &trace);
706 static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
710 vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
711 vec3_t original_origin;
712 vec3_t original_velocity;
713 vec3_t original_angles;
714 vec3_t original_avelocity;
717 VectorCopy(PRVM_serveredictvector(tossent, origin) , original_origin );
718 VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
719 VectorCopy(PRVM_serveredictvector(tossent, angles) , original_angles );
720 VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
722 gravity = PRVM_serveredictfloat(tossent, gravity);
725 gravity *= sv_gravity.value * 0.025;
727 for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
729 SV_CheckVelocity (tossent);
730 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
731 VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
732 VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
733 VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
734 VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
735 VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
736 VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
737 trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value);
738 VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
739 PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
741 if (trace.fraction < 1)
745 VectorCopy(original_origin , PRVM_serveredictvector(tossent, origin) );
746 VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
747 VectorCopy(original_angles , PRVM_serveredictvector(tossent, angles) );
748 VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
753 static void VM_SV_tracetoss(prvm_prog_t *prog)
757 prvm_edict_t *ignore;
759 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
761 prog->xfunction->builtinsprofile += 600;
763 ent = PRVM_G_EDICT(OFS_PARM0);
764 if (ent == prog->edicts)
766 VM_Warning(prog, "tracetoss: can not use world entity\n");
769 ignore = PRVM_G_EDICT(OFS_PARM1);
771 trace = SV_Trace_Toss(prog, ent, ignore);
773 VM_SetTraceGlobals(prog, &trace);
776 //============================================================================
778 static int checkpvsbytes;
779 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
781 static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
787 // cycle to the next one
789 check = bound(1, check, svs.maxclients);
790 if (check == svs.maxclients)
798 prog->xfunction->builtinsprofile++;
800 if (i == svs.maxclients+1)
802 // look up the client's edict
803 ent = PRVM_EDICT_NUM(i);
804 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
805 if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
807 // found a valid client (possibly the same one again)
811 // get the PVS for the entity
812 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
814 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
815 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
824 Returns a client (or object that has a client enemy) that would be a
827 If there is more than one valid option, they are cycled each frame
829 If (self.origin + self.viewofs) is not in the PVS of the current target,
830 it is not returned at all.
835 int c_invis, c_notvis;
836 static void VM_SV_checkclient(prvm_prog_t *prog)
838 prvm_edict_t *ent, *self;
841 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
843 // find a new check if on a new frame
844 if (sv.time - sv.lastchecktime >= 0.1)
846 sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
847 sv.lastchecktime = sv.time;
850 // return check if it might be visible
851 ent = PRVM_EDICT_NUM(sv.lastcheck);
852 if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
854 VM_RETURN_EDICT(prog->edicts);
858 // if current entity can't possibly see the check entity, return 0
859 self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
860 VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
861 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
864 VM_RETURN_EDICT(prog->edicts);
868 // might be able to see it
870 VM_RETURN_EDICT(ent);
873 //============================================================================
879 Checks if an entity is in a point's PVS.
880 Should be fast but can be inexact.
882 float checkpvs(vector viewpos, entity viewee) = #240;
885 static void VM_SV_checkpvs(prvm_prog_t *prog)
887 vec3_t viewpos, absmin, absmax;
888 prvm_edict_t *viewee;
893 unsigned char fatpvs[MAX_MAP_LEAFS/8];
896 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
897 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
898 viewee = PRVM_G_EDICT(OFS_PARM1);
900 if(viewee->priv.server->free)
902 VM_Warning(prog, "checkpvs: can not check free entity\n");
903 PRVM_G_FLOAT(OFS_RETURN) = 4;
908 if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
910 // no PVS support on this worldmodel... darn
911 PRVM_G_FLOAT(OFS_RETURN) = 3;
914 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
917 // viewpos isn't in any PVS... darn
918 PRVM_G_FLOAT(OFS_RETURN) = 2;
921 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
922 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
923 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
925 // using fat PVS like FTEQW does (slow)
926 if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
928 // no PVS support on this worldmodel... darn
929 PRVM_G_FLOAT(OFS_RETURN) = 3;
932 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
935 // viewpos isn't in any PVS... darn
936 PRVM_G_FLOAT(OFS_RETURN) = 2;
939 VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
940 VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
941 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
950 Sends text over to the client's execution buffer
952 stuffcmd (clientent, value, ...)
955 static void VM_SV_stuffcmd(prvm_prog_t *prog)
959 char string[VM_STRINGTEMP_LENGTH];
961 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
963 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
964 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
966 VM_Warning(prog, "Can't stuffcmd to a non-client\n");
970 VM_VarString(prog, 1, string, sizeof(string));
973 host_client = svs.clients + entnum-1;
974 SV_ClientCommands ("%s", string);
982 Returns a chain of entities that have origins within a spherical area
984 findradius (origin, radius)
987 static void VM_SV_findradius(prvm_prog_t *prog)
989 prvm_edict_t *ent, *chain;
990 vec_t radius, radius2;
991 vec3_t org, eorg, mins, maxs;
994 static prvm_edict_t *touchedicts[MAX_EDICTS];
997 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
1000 chainfield = PRVM_G_INT(OFS_PARM2);
1002 chainfield = prog->fieldoffsets.chain;
1004 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
1006 chain = (prvm_edict_t *)prog->edicts;
1008 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1009 radius = PRVM_G_FLOAT(OFS_PARM1);
1010 radius2 = radius * radius;
1012 mins[0] = org[0] - (radius + 1);
1013 mins[1] = org[1] - (radius + 1);
1014 mins[2] = org[2] - (radius + 1);
1015 maxs[0] = org[0] + (radius + 1);
1016 maxs[1] = org[1] + (radius + 1);
1017 maxs[2] = org[2] + (radius + 1);
1018 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1019 if (numtouchedicts > MAX_EDICTS)
1021 // this never happens
1022 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1023 numtouchedicts = MAX_EDICTS;
1025 for (i = 0;i < numtouchedicts;i++)
1027 ent = touchedicts[i];
1028 prog->xfunction->builtinsprofile++;
1029 // Quake did not return non-solid entities but darkplaces does
1030 // (note: this is the reason you can't blow up fallen zombies)
1031 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1033 // LadyHavoc: compare against bounding box rather than center so it
1034 // doesn't miss large objects, and use DotProduct instead of Length
1035 // for a major speedup
1036 VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
1037 if (sv_gameplayfix_findradiusdistancetobox.integer)
1039 eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
1040 eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
1041 eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
1044 VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
1045 if (DotProduct(eorg, eorg) < radius2)
1047 PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
1052 VM_RETURN_EDICT(chain);
1055 static void VM_SV_precache_sound(prvm_prog_t *prog)
1057 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1058 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1061 static void VM_SV_precache_model(prvm_prog_t *prog)
1063 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1064 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1065 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1072 float(float yaw, float dist[, settrace]) walkmove
1075 static void VM_SV_walkmove(prvm_prog_t *prog)
1084 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1086 // assume failure if it returns early
1087 PRVM_G_FLOAT(OFS_RETURN) = 0;
1089 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1090 if (ent == prog->edicts)
1092 VM_Warning(prog, "walkmove: can not modify world entity\n");
1095 if (ent->priv.server->free)
1097 VM_Warning(prog, "walkmove: can not modify free entity\n");
1100 yaw = PRVM_G_FLOAT(OFS_PARM0);
1101 dist = PRVM_G_FLOAT(OFS_PARM1);
1102 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1104 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1107 yaw = yaw*M_PI*2 / 360;
1109 move[0] = cos(yaw)*dist;
1110 move[1] = sin(yaw)*dist;
1113 // save program state, because SV_movestep may call other progs
1114 oldf = prog->xfunction;
1115 oldself = PRVM_serverglobaledict(self);
1117 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1120 // restore program state
1121 prog->xfunction = oldf;
1122 PRVM_serverglobaledict(self) = oldself;
1133 static void VM_SV_droptofloor(prvm_prog_t *prog)
1136 vec3_t end, entorigin, entmins, entmaxs;
1139 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1141 // assume failure if it returns early
1142 PRVM_G_FLOAT(OFS_RETURN) = 0;
1144 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1145 if (ent == prog->edicts)
1147 VM_Warning(prog, "droptofloor: can not modify world entity\n");
1150 if (ent->priv.server->free)
1152 VM_Warning(prog, "droptofloor: can not modify free entity\n");
1156 VectorCopy (PRVM_serveredictvector(ent, origin), end);
1159 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1160 SV_NudgeOutOfSolid(ent);
1162 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
1163 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
1164 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
1165 trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1166 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1169 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]);
1170 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
1171 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
1172 VectorSubtract(trace.endpos, offset, trace.endpos);
1173 if (trace.startsolid)
1175 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]);
1177 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1178 PRVM_serveredictedict(ent, groundentity) = 0;
1179 PRVM_G_FLOAT(OFS_RETURN) = 1;
1181 else if (trace.fraction < 1)
1183 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]);
1184 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1185 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1186 SV_NudgeOutOfSolid(ent);
1188 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1189 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1190 PRVM_G_FLOAT(OFS_RETURN) = 1;
1191 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1192 ent->priv.server->suspendedinairflag = true;
1197 if (!trace.allsolid && trace.fraction < 1)
1199 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
1201 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1202 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1203 PRVM_G_FLOAT(OFS_RETURN) = 1;
1204 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1205 ent->priv.server->suspendedinairflag = true;
1214 void(float style, string value) lightstyle
1217 static void VM_SV_lightstyle(prvm_prog_t *prog)
1224 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1226 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1227 val = PRVM_G_STRING(OFS_PARM1);
1229 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1230 prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
1233 // change the string in sv
1234 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1236 // send message to all clients on this server
1237 if (sv.state != ss_active)
1240 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1242 if (client->active && client->netconnection)
1244 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1245 MSG_WriteChar (&client->netconnection->message,style);
1246 MSG_WriteString (&client->netconnection->message, val);
1256 static void VM_SV_checkbottom(prvm_prog_t *prog)
1258 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1259 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1267 static void VM_SV_pointcontents(prvm_prog_t *prog)
1270 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1271 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
1272 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(point));
1279 Pick a vector for the player to shoot along
1280 vector aim(entity, missilespeed)
1283 static void VM_SV_aim(prvm_prog_t *prog)
1285 prvm_edict_t *ent, *check, *bestent;
1286 vec3_t start, dir, end, bestdir;
1289 float dist, bestdist;
1292 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1294 // assume failure if it returns early
1295 VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1296 // if sv_aim is so high it can't possibly accept anything, skip out early
1297 if (sv_aim.value >= 1)
1300 ent = PRVM_G_EDICT(OFS_PARM0);
1301 if (ent == prog->edicts)
1303 VM_Warning(prog, "aim: can not use world entity\n");
1306 if (ent->priv.server->free)
1308 VM_Warning(prog, "aim: can not use free entity\n");
1311 //speed = PRVM_G_FLOAT(OFS_PARM1);
1313 VectorCopy (PRVM_serveredictvector(ent, origin), start);
1316 // try sending a trace straight
1317 VectorCopy (PRVM_serverglobalvector(v_forward), dir);
1318 VectorMA (start, 2048, dir, end);
1319 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1320 if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
1321 && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
1323 VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
1328 // try all possible entities
1329 VectorCopy (dir, bestdir);
1330 bestdist = sv_aim.value;
1333 check = PRVM_NEXT_EDICT(prog->edicts);
1334 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1336 prog->xfunction->builtinsprofile++;
1337 if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
1341 if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
1342 continue; // don't aim at teammate
1343 for (j=0 ; j<3 ; j++)
1344 end[j] = PRVM_serveredictvector(check, origin)[j]
1345 + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
1346 VectorSubtract (end, start, dir);
1347 VectorNormalize (dir);
1348 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1349 if (dist < bestdist)
1350 continue; // to far to turn
1351 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1352 if (tr.ent == check)
1353 { // can shoot at this one
1361 VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
1362 dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
1363 VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
1365 VectorNormalize (end);
1366 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1370 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1375 ===============================================================================
1379 ===============================================================================
1382 #define MSG_BROADCAST 0 // unreliable to all
1383 #define MSG_ONE 1 // reliable to one (msg_entity)
1384 #define MSG_ALL 2 // reliable to all
1385 #define MSG_INIT 3 // write to the init string
1386 #define MSG_ENTITY 5
1388 static sizebuf_t *WriteDest(prvm_prog_t *prog)
1394 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1398 return &sv.datagram;
1401 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
1402 entnum = PRVM_NUM_FOR_EDICT(ent);
1403 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1405 VM_Warning(prog, "WriteDest: tried to write to non-client\n");
1406 return &sv.reliable_datagram;
1409 return &svs.clients[entnum-1].netconnection->message;
1412 VM_Warning(prog, "WriteDest: bad destination\n");
1414 return &sv.reliable_datagram;
1420 return sv.writeentitiestoclient_msg;
1426 static void VM_SV_WriteByte(prvm_prog_t *prog)
1428 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1429 MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1432 static void VM_SV_WriteChar(prvm_prog_t *prog)
1434 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1435 MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1438 static void VM_SV_WriteShort(prvm_prog_t *prog)
1440 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1441 MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1444 static void VM_SV_WriteLong(prvm_prog_t *prog)
1446 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1447 MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
1450 static void VM_SV_WriteAngle(prvm_prog_t *prog)
1452 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1453 MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1456 static void VM_SV_WriteCoord(prvm_prog_t *prog)
1458 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1459 MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1462 static void VM_SV_WriteString(prvm_prog_t *prog)
1464 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1465 MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1468 static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
1470 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1471 MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
1475 static void VM_SV_WriteEntity(prvm_prog_t *prog)
1477 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1478 MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
1481 // writes a picture as at most size bytes of data
1483 // IMGNAME \0 SIZE(short) IMGDATA
1484 // if failed to read/compress:
1486 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1487 static void VM_SV_WritePicture(prvm_prog_t *prog)
1489 const char *imgname;
1493 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1495 imgname = PRVM_G_STRING(OFS_PARM1);
1496 size = (size_t) PRVM_G_FLOAT(OFS_PARM2);
1500 MSG_WriteString(WriteDest(prog), imgname);
1501 if(Image_Compress(imgname, size, &buf, &size))
1504 MSG_WriteShort(WriteDest(prog), (int)size);
1505 SZ_Write(WriteDest(prog), (unsigned char *) buf, (int)size);
1510 MSG_WriteShort(WriteDest(prog), 0);
1514 //////////////////////////////////////////////////////////
1516 static void VM_SV_makestatic(prvm_prog_t *prog)
1521 // allow 0 parameters due to an id1 qc bug in which this function is used
1522 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1523 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1525 if (prog->argc >= 1)
1526 ent = PRVM_G_EDICT(OFS_PARM0);
1528 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
1529 if (ent == prog->edicts)
1531 VM_Warning(prog, "makestatic: can not modify world entity\n");
1534 if (ent->priv.server->free)
1536 VM_Warning(prog, "makestatic: can not modify free entity\n");
1541 if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
1546 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1547 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1548 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1550 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1552 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1553 MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1554 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1558 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1559 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
1560 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
1563 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
1564 MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
1565 for (i=0 ; i<3 ; i++)
1567 MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
1568 MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
1571 // throw the entity away now
1572 PRVM_ED_Free(prog, ent);
1575 //=============================================================================
1582 static void VM_SV_setspawnparms(prvm_prog_t *prog)
1588 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1590 ent = PRVM_G_EDICT(OFS_PARM0);
1591 i = PRVM_NUM_FOR_EDICT(ent);
1592 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1594 Con_Print("tried to setspawnparms on a non-client\n");
1598 // copy spawn parms out of the client_t
1599 client = svs.clients + i-1;
1600 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1601 (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
1608 Returns a color vector indicating the lighting at the requested point.
1610 (Internal Operation note: actually measures the light beneath the point, just like
1611 the model lighting on the client)
1616 static void VM_SV_getlight(prvm_prog_t *prog)
1618 vec3_t ambientcolor, diffusecolor, diffusenormal;
1620 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1621 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
1622 VectorClear(ambientcolor);
1623 VectorClear(diffusecolor);
1624 VectorClear(diffusenormal);
1625 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1626 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1627 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1632 unsigned char type; // 1/2/8 or 0 to indicate unused
1636 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)
1637 static int vm_customstats_last;
1639 void VM_CustomStats_Clear (void)
1641 memset(vm_customstats, 0, sizeof(vm_customstats));
1642 vm_customstats_last = -1;
1645 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1647 prvm_prog_t *prog = SVVM_prog;
1655 for(i=MIN_VM_STAT; i<=vm_customstats_last ;i++)
1657 if(!vm_customstats[i].type)
1659 switch(vm_customstats[i].type)
1661 //string as 16 bytes
1664 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1665 stats[i] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1666 stats[i+1] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1667 stats[i+2] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1668 stats[i+3] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1670 //float field sent as-is
1672 // 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
1673 u.f = PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1676 //integer value of float field
1678 stats[i] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1686 extern cvar_t sv_gameplayfix_customstats;
1688 // void(float index, float type, .void field) SV_AddStat = #232;
1689 // Set up an auto-sent player stat.
1690 // Client's get thier own fields sent to them. Index may not be less than 32.
1691 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1692 // 1: string (4 stats carrying a total of 16 charactures)
1693 // 2: float (one stat, float converted to an integer for transportation)
1694 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1695 static void VM_SV_AddStat(prvm_prog_t *prog)
1699 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1701 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1702 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1703 off = PRVM_G_INT (OFS_PARM2);
1712 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);
1718 VM_Warning(prog, "PF_SV_AddStat: index (%i) may not be less than %i\n", i, MIN_VM_STAT);
1722 if (i >= MAX_CL_STATS)
1724 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);
1728 if (i > (MAX_CL_STATS - 4) && type == 1)
1730 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);
1734 // these are hazardous to override but sort of allowed if one wants to be adventurous... and enjoys warnings.
1735 if (i < MIN_VM_STAT)
1736 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);
1737 else if (i >= MAX_VM_STAT && !sv_gameplayfix_customstats.integer)
1738 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);
1739 else if (i > (MAX_VM_STAT - 4) && type == 1 && !sv_gameplayfix_customstats.integer)
1740 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);
1742 vm_customstats[i].type = type;
1743 vm_customstats[i].fieldoffset = off;
1744 if(vm_customstats_last < i)
1745 vm_customstats_last = i;
1752 copies data from one entity to another
1754 copyentity(src, dst)
1757 static void VM_SV_copyentity(prvm_prog_t *prog)
1759 prvm_edict_t *in, *out;
1760 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1761 in = PRVM_G_EDICT(OFS_PARM0);
1762 if (in == prog->edicts)
1764 VM_Warning(prog, "copyentity: can not read world entity\n");
1767 if (in->priv.server->free)
1769 VM_Warning(prog, "copyentity: can not read free entity\n");
1772 out = PRVM_G_EDICT(OFS_PARM1);
1773 if (out == prog->edicts)
1775 VM_Warning(prog, "copyentity: can not modify world entity\n");
1778 if (out->priv.server->free)
1780 VM_Warning(prog, "copyentity: can not modify free entity\n");
1783 memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
1784 if (VectorCompare(PRVM_serveredictvector(out, absmin), PRVM_serveredictvector(out, absmax)))
1794 sets the color of a client and broadcasts the update to all connected clients
1796 setcolor(clientent, value)
1799 static void VM_SV_setcolor(prvm_prog_t *prog)
1804 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1805 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1806 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1808 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1810 Con_Print("tried to setcolor a non-client\n");
1814 client = svs.clients + entnum-1;
1817 PRVM_serveredictfloat(client->edict, clientcolors) = i;
1818 PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
1821 if (client->old_colors != client->colors)
1823 client->old_colors = client->colors;
1824 // send notification to all clients
1825 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1826 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1827 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1835 effect(origin, modelname, startframe, framecount, framerate)
1838 static void VM_SV_effect(prvm_prog_t *prog)
1843 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1844 s = PRVM_G_STRING(OFS_PARM1);
1847 VM_Warning(prog, "effect: no model specified\n");
1851 i = SV_ModelIndex(s, 1);
1854 VM_Warning(prog, "effect: model not precached\n");
1858 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1860 VM_Warning(prog, "effect: framecount < 1\n");
1864 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1866 VM_Warning(prog, "effect: framerate < 1\n");
1870 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1871 SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1874 static void VM_SV_te_blood(prvm_prog_t *prog)
1876 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1877 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1879 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1880 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1882 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1886 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1887 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1888 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1890 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1891 SV_FlushBroadcastMessages();
1894 static void VM_SV_te_bloodshower(prvm_prog_t *prog)
1896 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1897 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1899 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1900 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1902 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1903 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1904 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1906 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1908 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1912 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1913 SV_FlushBroadcastMessages();
1916 static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
1918 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1919 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1920 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1922 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1923 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1924 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1926 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1927 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1928 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1929 SV_FlushBroadcastMessages();
1932 static void VM_SV_te_particlecube(prvm_prog_t *prog)
1934 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1935 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1937 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1938 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1940 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1941 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1942 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1944 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1945 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1946 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1948 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1949 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1950 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1952 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1954 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1955 // gravity true/false
1956 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1958 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1959 SV_FlushBroadcastMessages();
1962 static void VM_SV_te_particlerain(prvm_prog_t *prog)
1964 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1965 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1967 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1968 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1970 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1971 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1972 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1974 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1976 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1978 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1979 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1980 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1982 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1984 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1985 SV_FlushBroadcastMessages();
1988 static void VM_SV_te_particlesnow(prvm_prog_t *prog)
1990 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1991 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1993 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1994 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1996 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1997 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1998 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2000 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2002 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2004 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2005 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2006 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2008 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2010 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
2011 SV_FlushBroadcastMessages();
2014 static void VM_SV_te_spark(prvm_prog_t *prog)
2016 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
2017 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2019 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2020 MSG_WriteByte(&sv.datagram, TE_SPARK);
2022 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2023 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2024 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2026 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2027 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2028 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2030 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2031 SV_FlushBroadcastMessages();
2034 static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
2036 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
2037 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2038 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2040 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2041 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2042 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2043 SV_FlushBroadcastMessages();
2046 static void VM_SV_te_spikequad(prvm_prog_t *prog)
2048 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2049 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2050 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2052 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2053 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2054 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2055 SV_FlushBroadcastMessages();
2058 static void VM_SV_te_superspikequad(prvm_prog_t *prog)
2060 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2061 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2062 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2064 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2065 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2066 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2067 SV_FlushBroadcastMessages();
2070 static void VM_SV_te_explosionquad(prvm_prog_t *prog)
2072 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2073 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2074 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2076 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2077 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2078 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2079 SV_FlushBroadcastMessages();
2082 static void VM_SV_te_smallflash(prvm_prog_t *prog)
2084 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2085 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2086 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2088 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2089 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2090 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2091 SV_FlushBroadcastMessages();
2094 static void VM_SV_te_customflash(prvm_prog_t *prog)
2096 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2097 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2099 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2100 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2102 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2103 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2104 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2106 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2108 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2110 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2111 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2112 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2113 SV_FlushBroadcastMessages();
2116 static void VM_SV_te_gunshot(prvm_prog_t *prog)
2118 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2119 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2120 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2122 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2123 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2124 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2125 SV_FlushBroadcastMessages();
2128 static void VM_SV_te_spike(prvm_prog_t *prog)
2130 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2131 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2132 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2134 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2135 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2136 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2137 SV_FlushBroadcastMessages();
2140 static void VM_SV_te_superspike(prvm_prog_t *prog)
2142 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2143 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2144 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2146 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2147 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2148 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2149 SV_FlushBroadcastMessages();
2152 static void VM_SV_te_explosion(prvm_prog_t *prog)
2154 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2155 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2156 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2158 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2159 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2160 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2161 SV_FlushBroadcastMessages();
2164 static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
2166 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2167 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2168 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2170 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2171 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2172 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2173 SV_FlushBroadcastMessages();
2176 static void VM_SV_te_wizspike(prvm_prog_t *prog)
2178 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2179 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2180 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2182 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2185 SV_FlushBroadcastMessages();
2188 static void VM_SV_te_knightspike(prvm_prog_t *prog)
2190 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2191 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2192 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2194 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2195 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2196 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2197 SV_FlushBroadcastMessages();
2200 static void VM_SV_te_lavasplash(prvm_prog_t *prog)
2202 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2203 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2204 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2206 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2207 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2208 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2209 SV_FlushBroadcastMessages();
2212 static void VM_SV_te_teleport(prvm_prog_t *prog)
2214 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2215 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2216 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2218 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2221 SV_FlushBroadcastMessages();
2224 static void VM_SV_te_explosion2(prvm_prog_t *prog)
2226 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2227 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2228 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2230 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2231 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2232 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2234 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2235 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2236 SV_FlushBroadcastMessages();
2239 static void VM_SV_te_lightning1(prvm_prog_t *prog)
2241 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2242 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2243 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2245 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2247 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2248 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2249 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2251 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2252 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2253 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2254 SV_FlushBroadcastMessages();
2257 static void VM_SV_te_lightning2(prvm_prog_t *prog)
2259 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2260 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2261 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2263 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2265 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2266 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2267 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2272 SV_FlushBroadcastMessages();
2275 static void VM_SV_te_lightning3(prvm_prog_t *prog)
2277 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2278 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2279 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2281 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2283 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2284 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2285 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2287 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2288 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2290 SV_FlushBroadcastMessages();
2293 static void VM_SV_te_beam(prvm_prog_t *prog)
2295 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2296 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2297 MSG_WriteByte(&sv.datagram, TE_BEAM);
2299 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2301 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2302 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2305 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2308 SV_FlushBroadcastMessages();
2311 static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
2313 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2314 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2315 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2316 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2317 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2318 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2319 SV_FlushBroadcastMessages();
2322 static void VM_SV_te_flamejet(prvm_prog_t *prog)
2324 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2325 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2326 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2328 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2334 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2336 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2337 SV_FlushBroadcastMessages();
2340 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2341 //this function originally written by KrimZon, made shorter by LadyHavoc
2342 static void VM_SV_clientcommand(prvm_prog_t *prog)
2344 client_t *temp_client;
2346 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2348 //find client for this entity
2349 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2350 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2352 Con_Print("PF_clientcommand: entity is not a client\n");
2356 temp_client = host_client;
2357 host_client = svs.clients + i;
2358 Cmd_ExecuteString(&cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
2359 host_client = temp_client;
2362 //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)
2363 static void VM_SV_setattachment(prvm_prog_t *prog)
2365 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2366 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2367 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2370 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2372 if (e == prog->edicts)
2374 VM_Warning(prog, "setattachment: can not modify world entity\n");
2377 if (e->priv.server->free)
2379 VM_Warning(prog, "setattachment: can not modify free entity\n");
2383 if (tagentity == NULL)
2384 tagentity = prog->edicts;
2388 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2390 model = SV_GetModelFromEdict(tagentity);
2393 tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
2395 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);
2398 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));
2401 PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
2402 PRVM_serveredictfloat(e, tag_index) = tagindex;
2405 /////////////////////////////////////////
2406 // DP_MD3_TAGINFO extension coded by VorteX
2408 static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
2412 i = (int)PRVM_serveredictfloat(e, modelindex);
2413 if (i < 1 || i >= MAX_MODELS)
2416 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
2419 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2426 Matrix4x4_CreateIdentity(tag_localmatrix);
2428 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2430 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2441 void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2444 float pitchsign = 1;
2446 scale = PRVM_serveredictfloat(ent, scale);
2451 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);
2454 pitchsign = SV_GetPitchSign(prog, ent);
2455 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);
2459 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2462 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2464 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2465 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2466 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2467 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2469 *out = identitymatrix;
2473 // Warnings/errors code:
2474 // 0 - normal (everything all-right)
2477 // 3 - null or non-precached model
2478 // 4 - no tags with requested index
2479 // 5 - runaway loop at attachment chain
2480 extern cvar_t cl_bob;
2481 extern cvar_t cl_bobcycle;
2482 extern cvar_t cl_bobup;
2483 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2486 int modelindex, attachloop;
2487 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2490 *out = identitymatrix; // warnings and errors return identical matrix
2492 if (ent == prog->edicts)
2494 if (ent->priv.server->free)
2497 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
2498 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2501 model = SV_GetModelByIndex(modelindex);
2503 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
2504 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
2505 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
2507 tagmatrix = identitymatrix;
2508 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2512 if (attachloop >= 256) // prevent runaway looping
2514 // apply transformation by child's tagindex on parent entity and then
2515 // by parent entity itself
2516 ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
2517 if (ret && attachloop == 0)
2519 SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
2520 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2521 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2522 // next iteration we process the parent entity
2523 if (PRVM_serveredictedict(ent, tag_entity))
2525 tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
2526 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
2533 // RENDER_VIEWMODEL magic
2534 if (PRVM_serveredictedict(ent, viewmodelforclient))
2536 Matrix4x4_Copy(&tagmatrix, out);
2537 ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
2539 SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
2540 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2543 // Cl_bob, ported from rendering code
2544 if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
2547 // LadyHavoc: this code is *weird*, but not replacable (I think it
2548 // should be done in QC on the server, but oh well, quake is quake)
2549 // LadyHavoc: figured out bobup: the time at which the sin is at 180
2550 // degrees (which allows lengthening or squishing the peak or valley)
2551 cycle = sv.time/cl_bobcycle.value;
2552 cycle -= (int)cycle;
2553 if (cycle < cl_bobup.value)
2554 cycle = sin(M_PI * cycle / cl_bobup.value);
2556 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2557 // bob is proportional to velocity in the xy plane
2558 // (don't count Z, or jumping messes it up)
2559 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;
2560 bob = bob*0.3 + bob*0.7*cycle;
2561 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2568 //float(entity ent, string tagname) gettagindex;
2570 static void VM_SV_gettagindex(prvm_prog_t *prog)
2573 const char *tag_name;
2576 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2578 ent = PRVM_G_EDICT(OFS_PARM0);
2579 tag_name = PRVM_G_STRING(OFS_PARM1);
2581 if (ent == prog->edicts)
2583 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2586 if (ent->priv.server->free)
2588 VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2593 if (!SV_GetModelFromEdict(ent))
2594 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2597 tag_index = SV_GetTagIndex(prog, ent, tag_name);
2599 if(developer_extra.integer)
2600 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2602 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2605 //vector(entity ent, float tagindex) gettaginfo;
2606 static void VM_SV_gettaginfo(prvm_prog_t *prog)
2610 matrix4x4_t tag_matrix;
2611 matrix4x4_t tag_localmatrix;
2613 const char *tagname;
2615 vec3_t forward, left, up, origin;
2616 const dp_model_t *model;
2618 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2620 e = PRVM_G_EDICT(OFS_PARM0);
2621 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2623 returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
2624 Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
2625 VectorCopy(forward, PRVM_serverglobalvector(v_forward));
2626 VectorNegate(left, PRVM_serverglobalvector(v_right));
2627 VectorCopy(up, PRVM_serverglobalvector(v_up));
2628 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
2629 model = SV_GetModelFromEdict(e);
2630 VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
2631 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
2632 VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
2633 SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2634 Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
2636 PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
2637 PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
2638 VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
2639 VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
2640 VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
2641 VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
2646 VM_Warning(prog, "gettagindex: can't affect world entity\n");
2649 VM_Warning(prog, "gettagindex: can't affect free entity\n");
2652 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2655 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2658 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2663 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2664 static void VM_SV_dropclient(prvm_prog_t *prog)
2667 client_t *oldhostclient;
2668 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2669 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2670 if (clientnum < 0 || clientnum >= svs.maxclients)
2672 VM_Warning(prog, "dropclient: not a client\n");
2675 if (!svs.clients[clientnum].active)
2677 VM_Warning(prog, "dropclient: that client slot is not connected\n");
2680 oldhostclient = host_client;
2681 host_client = svs.clients + clientnum;
2682 SV_DropClient(false);
2683 host_client = oldhostclient;
2686 //entity() spawnclient (DP_SV_BOTCLIENT)
2687 static void VM_SV_spawnclient(prvm_prog_t *prog)
2691 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2692 prog->xfunction->builtinsprofile += 2;
2694 for (i = 0;i < svs.maxclients;i++)
2696 if (!svs.clients[i].active)
2698 prog->xfunction->builtinsprofile += 100;
2699 SV_ConnectClient (i, NULL);
2700 // this has to be set or else ClientDisconnect won't be called
2701 // we assume the qc will call ClientConnect...
2702 svs.clients[i].clientconnectcalled = true;
2703 ed = PRVM_EDICT_NUM(i + 1);
2707 VM_RETURN_EDICT(ed);
2710 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2711 static void VM_SV_clienttype(prvm_prog_t *prog)
2714 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2715 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2716 if (clientnum < 0 || clientnum >= svs.maxclients)
2717 PRVM_G_FLOAT(OFS_RETURN) = 3;
2718 else if (!svs.clients[clientnum].active)
2719 PRVM_G_FLOAT(OFS_RETURN) = 0;
2720 else if (svs.clients[clientnum].netconnection)
2721 PRVM_G_FLOAT(OFS_RETURN) = 1;
2723 PRVM_G_FLOAT(OFS_RETURN) = 2;
2730 string(string key) serverkey
2733 static void VM_SV_serverkey(prvm_prog_t *prog)
2735 char string[VM_STRINGTEMP_LENGTH];
2736 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2737 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2738 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2741 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2742 static void VM_SV_setmodelindex(prvm_prog_t *prog)
2747 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2749 e = PRVM_G_EDICT(OFS_PARM0);
2750 if (e == prog->edicts)
2752 VM_Warning(prog, "setmodelindex: can not modify world entity\n");
2755 if (e->priv.server->free)
2757 VM_Warning(prog, "setmodelindex: can not modify free entity\n");
2760 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2761 if (i <= 0 || i >= MAX_MODELS)
2763 VM_Warning(prog, "setmodelindex: invalid modelindex\n");
2766 if (!sv.model_precache[i][0])
2768 VM_Warning(prog, "setmodelindex: model not precached\n");
2772 PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2773 PRVM_serveredictfloat(e, modelindex) = i;
2775 mod = SV_GetModelByIndex(i);
2779 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2780 SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
2782 SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
2785 SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
2788 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2789 static void VM_SV_modelnameforindex(prvm_prog_t *prog)
2792 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2794 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2796 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2797 if (i <= 0 || i >= MAX_MODELS)
2799 VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
2802 if (!sv.model_precache[i][0])
2804 VM_Warning(prog, "modelnameforindex: model not precached\n");
2808 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
2811 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2812 static void VM_SV_particleeffectnum(prvm_prog_t *prog)
2815 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2816 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2819 PRVM_G_FLOAT(OFS_RETURN) = i;
2822 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2823 static void VM_SV_trailparticles(prvm_prog_t *prog)
2826 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2828 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2831 MSG_WriteByte(&sv.datagram, svc_trailparticles);
2832 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2833 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2834 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2835 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2836 MSG_WriteVector(&sv.datagram, start, sv.protocol);
2837 MSG_WriteVector(&sv.datagram, end, sv.protocol);
2838 SV_FlushBroadcastMessages();
2841 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
2842 static void VM_SV_pointparticles(prvm_prog_t *prog)
2844 int effectnum, count;
2846 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
2848 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2851 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2852 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
2853 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2854 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
2855 if (count == 1 && !VectorLength2(vel))
2858 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
2859 MSG_WriteShort(&sv.datagram, effectnum);
2860 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2864 // 1+2+12+12+2=29 bytes
2865 MSG_WriteByte(&sv.datagram, svc_pointparticles);
2866 MSG_WriteShort(&sv.datagram, effectnum);
2867 MSG_WriteVector(&sv.datagram, org, sv.protocol);
2868 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
2869 MSG_WriteShort(&sv.datagram, count);
2872 SV_FlushBroadcastMessages();
2875 //PF_setpause, // void(float pause) setpause = #531;
2876 static void VM_SV_setpause(prvm_prog_t *prog) {
2878 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
2879 if (pauseValue != 0) { //pause the game
2881 sv.pausedstart = host.realtime;
2882 } else { //disable pause, in case it was enabled
2883 if (sv.paused != 0) {
2888 // send notification to all clients
2889 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
2890 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
2893 // #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.
2894 static void VM_SV_skel_create(prvm_prog_t *prog)
2896 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
2897 dp_model_t *model = SV_GetModelByIndex(modelindex);
2898 skeleton_t *skeleton;
2900 PRVM_G_FLOAT(OFS_RETURN) = 0;
2901 if (!model || !model->num_bones)
2903 for (i = 0;i < MAX_EDICTS;i++)
2904 if (!prog->skeletons[i])
2906 if (i == MAX_EDICTS)
2908 prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
2909 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
2910 skeleton->model = model;
2911 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
2912 // initialize to identity matrices
2913 for (i = 0;i < skeleton->model->num_bones;i++)
2914 skeleton->relativetransforms[i] = identitymatrix;
2917 // #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
2918 static void VM_SV_skel_build(prvm_prog_t *prog)
2920 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2921 skeleton_t *skeleton;
2922 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
2923 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
2924 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
2925 int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
2926 int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
2927 dp_model_t *model = SV_GetModelByIndex(modelindex);
2931 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
2932 frameblend_t frameblend[MAX_FRAMEBLENDS];
2933 matrix4x4_t bonematrix;
2935 PRVM_G_FLOAT(OFS_RETURN) = 0;
2936 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2938 firstbone = max(0, firstbone);
2939 lastbone = min(lastbone, model->num_bones - 1);
2940 lastbone = min(lastbone, skeleton->model->num_bones - 1);
2941 VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
2942 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
2943 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
2945 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
2947 memset(&bonematrix, 0, sizeof(bonematrix));
2948 for (blendindex = 0;blendindex < numblends;blendindex++)
2950 Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
2951 Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
2953 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
2954 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
2956 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
2959 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
2960 static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
2962 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2963 skeleton_t *skeleton;
2964 PRVM_G_FLOAT(OFS_RETURN) = 0;
2965 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2967 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
2970 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
2971 static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
2973 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2974 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2975 skeleton_t *skeleton;
2976 PRVM_G_INT(OFS_RETURN) = 0;
2977 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2979 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2981 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
2984 // #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)
2985 static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
2987 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
2988 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
2989 skeleton_t *skeleton;
2990 PRVM_G_FLOAT(OFS_RETURN) = 0;
2991 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
2993 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
2995 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
2998 // #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
2999 static void VM_SV_skel_find_bone(prvm_prog_t *prog)
3001 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3002 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3003 skeleton_t *skeleton;
3004 PRVM_G_FLOAT(OFS_RETURN) = 0;
3005 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3007 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3010 // #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)
3011 static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
3013 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3014 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3015 skeleton_t *skeleton;
3017 vec3_t forward, left, up, origin;
3018 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3019 VectorClear(PRVM_clientglobalvector(v_forward));
3020 VectorClear(PRVM_clientglobalvector(v_right));
3021 VectorClear(PRVM_clientglobalvector(v_up));
3022 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3024 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3026 matrix = skeleton->relativetransforms[bonenum];
3027 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3028 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3029 VectorNegate(left, PRVM_clientglobalvector(v_right));
3030 VectorCopy(up, PRVM_clientglobalvector(v_up));
3031 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3034 // #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)
3035 static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
3037 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3038 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3039 skeleton_t *skeleton;
3042 vec3_t forward, left, up, origin;
3043 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3044 VectorClear(PRVM_clientglobalvector(v_forward));
3045 VectorClear(PRVM_clientglobalvector(v_right));
3046 VectorClear(PRVM_clientglobalvector(v_up));
3047 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3049 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3051 matrix = skeleton->relativetransforms[bonenum];
3052 // convert to absolute
3053 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3056 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3058 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3059 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3060 VectorNegate(left, PRVM_clientglobalvector(v_right));
3061 VectorCopy(up, PRVM_clientglobalvector(v_up));
3062 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3065 // #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)
3066 static void VM_SV_skel_set_bone(prvm_prog_t *prog)
3068 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3069 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3070 vec3_t forward, left, up, origin;
3071 skeleton_t *skeleton;
3073 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3075 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3077 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3078 VectorNegate(PRVM_clientglobalvector(v_right), left);
3079 VectorCopy(PRVM_clientglobalvector(v_up), up);
3080 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3081 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3082 skeleton->relativetransforms[bonenum] = matrix;
3085 // #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)
3086 static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
3088 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3089 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3090 vec3_t forward, left, up, origin;
3091 skeleton_t *skeleton;
3094 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3096 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3098 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3099 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3100 VectorNegate(PRVM_clientglobalvector(v_right), left);
3101 VectorCopy(PRVM_clientglobalvector(v_up), up);
3102 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3103 temp = skeleton->relativetransforms[bonenum];
3104 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3107 // #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)
3108 static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
3110 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3111 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3112 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3114 vec3_t forward, left, up, origin;
3115 skeleton_t *skeleton;
3118 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3120 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3121 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
3122 VectorNegate(PRVM_clientglobalvector(v_right), left);
3123 VectorCopy(PRVM_clientglobalvector(v_up), up);
3124 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3125 firstbone = max(0, firstbone);
3126 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3127 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3129 temp = skeleton->relativetransforms[bonenum];
3130 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3134 // #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
3135 static void VM_SV_skel_copybones(prvm_prog_t *prog)
3137 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3138 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3139 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3140 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3142 skeleton_t *skeletondst;
3143 skeleton_t *skeletonsrc;
3144 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3146 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3148 firstbone = max(0, firstbone);
3149 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3150 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3151 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3152 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3155 // #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)
3156 static void VM_SV_skel_delete(prvm_prog_t *prog)
3158 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3159 skeleton_t *skeleton;
3160 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3163 prog->skeletons[skeletonindex] = NULL;
3166 // #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
3167 static void VM_SV_frameforname(prvm_prog_t *prog)
3169 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3170 dp_model_t *model = SV_GetModelByIndex(modelindex);
3171 const char *name = PRVM_G_STRING(OFS_PARM1);
3173 PRVM_G_FLOAT(OFS_RETURN) = -1;
3174 if (!model || !model->animscenes)
3176 for (i = 0;i < model->numframes;i++)
3178 if (!strcasecmp(model->animscenes[i].name, name))
3180 PRVM_G_FLOAT(OFS_RETURN) = i;
3186 // #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.
3187 static void VM_SV_frameduration(prvm_prog_t *prog)
3189 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3190 dp_model_t *model = SV_GetModelByIndex(modelindex);
3191 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3192 PRVM_G_FLOAT(OFS_RETURN) = 0;
3193 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3195 if (model->animscenes[framenum].framerate)
3196 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3200 prvm_builtin_t vm_sv_builtins[] = {
3201 NULL, // #0 NULL function (not callable) (QUAKE)
3202 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3203 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3204 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3205 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3206 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3207 VM_break, // #6 void() break (QUAKE)
3208 VM_random, // #7 float() random (QUAKE)
3209 VM_SV_sound, // #8 void(entity e, float chan, string samp, float volume[, float atten[, float pitchchange[, float flags]]]) sound (QUAKE)
3210 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3211 VM_error, // #10 void(string e) error (QUAKE)
3212 VM_objerror, // #11 void(string e) objerror (QUAKE)
3213 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3214 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3215 VM_spawn, // #14 entity() spawn (QUAKE)
3216 VM_remove, // #15 void(entity e) remove (QUAKE)
3217 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3218 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3219 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3220 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3221 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3222 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3223 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3224 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3225 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3226 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3227 VM_ftos, // #26 string(float f) ftos (QUAKE)
3228 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3229 VM_coredump, // #28 void() coredump (QUAKE)
3230 VM_traceon, // #29 void() traceon (QUAKE)
3231 VM_traceoff, // #30 void() traceoff (QUAKE)
3232 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3233 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3234 NULL, // #33 (QUAKE)
3235 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3236 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3237 VM_rint, // #36 float(float v) rint (QUAKE)
3238 VM_floor, // #37 float(float v) floor (QUAKE)
3239 VM_ceil, // #38 float(float v) ceil (QUAKE)
3240 NULL, // #39 (QUAKE)
3241 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3242 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3243 NULL, // #42 (QUAKE)
3244 VM_fabs, // #43 float(float f) fabs (QUAKE)
3245 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3246 VM_cvar, // #45 float(string s) cvar (QUAKE)
3247 VM_localcmd_server, // #46 void(string s) localcmd (QUAKE)
3248 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3249 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3250 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3251 NULL, // #50 (QUAKE)
3252 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3253 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3254 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3255 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3256 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3257 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3258 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3259 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3260 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3261 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3262 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3263 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3264 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3265 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3266 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3267 NULL, // #66 (QUAKE)
3268 VM_SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3269 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3270 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3271 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3272 NULL, // #71 (QUAKE)
3273 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3274 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3275 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3276 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3277 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3278 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3279 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3280 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3281 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3282 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3283 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3284 NULL, // #83 (QUAKE)
3285 NULL, // #84 (QUAKE)
3286 NULL, // #85 (QUAKE)
3287 NULL, // #86 (QUAKE)
3288 NULL, // #87 (QUAKE)
3289 NULL, // #88 (QUAKE)
3290 NULL, // #89 (QUAKE)
3291 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3292 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3293 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3294 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3295 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3296 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3297 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3298 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3299 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3300 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3301 // FrikaC and Telejano range #100-#199
3312 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3313 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3314 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3315 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3316 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3317 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3318 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3319 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3320 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3321 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3402 // FTEQW range #200-#299
3421 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3424 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3425 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3426 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3427 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3428 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3429 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3430 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3431 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3432 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3433 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3435 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3443 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3466 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.
3467 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
3468 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3469 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3470 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)
3471 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
3472 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)
3473 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)
3474 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)
3475 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)
3476 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)
3477 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
3478 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)
3479 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
3480 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.
3503 // CSQC range #300-#399
3504 NULL, // #300 void() clearscene (EXT_CSQC)
3505 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3506 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3507 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3508 NULL, // #304 void() renderscene (EXT_CSQC)
3509 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3510 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3511 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3512 NULL, // #308 void() R_EndPolygon
3514 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3515 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3519 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3520 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3521 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3522 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3523 NULL, // #319 void(string name) freepic (EXT_CSQC)
3524 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3525 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3526 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3527 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3528 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3529 NULL, // #325 void(void) drawresetcliparea
3534 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3535 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3536 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3537 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3538 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3539 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3540 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3541 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3542 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3543 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3544 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3545 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3546 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3547 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3548 NULL, // #344 vector() getmousepos (EXT_CSQC)
3549 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3550 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3551 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3552 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3553 NULL, // #349 float() isdemo (EXT_CSQC)
3554 VM_isserver, // #350 float() isserver (EXT_CSQC)
3555 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3556 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3557 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3558 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3564 NULL, // #360 float() readbyte (EXT_CSQC)
3565 NULL, // #361 float() readchar (EXT_CSQC)
3566 NULL, // #362 float() readshort (EXT_CSQC)
3567 NULL, // #363 float() readlong (EXT_CSQC)
3568 NULL, // #364 float() readcoord (EXT_CSQC)
3569 NULL, // #365 float() readangle (EXT_CSQC)
3570 NULL, // #366 string() readstring (EXT_CSQC)
3571 NULL, // #367 float() readfloat (EXT_CSQC)
3604 // LadyHavoc's range #400-#499
3605 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3606 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3607 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3608 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3609 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3610 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3611 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3612 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3613 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)
3614 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3615 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3616 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3617 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3618 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3619 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3620 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3621 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3622 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3623 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3624 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3625 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3626 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3627 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3628 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3629 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3630 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3631 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3632 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3633 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3634 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3635 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3636 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3637 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3638 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3639 VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3640 VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3641 VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3642 VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3643 VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3644 VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3645 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3646 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3647 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3648 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3649 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3650 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3651 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3652 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3653 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3654 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3655 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3656 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3657 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3658 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3659 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3660 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3661 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3662 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3664 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3665 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3666 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3667 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3668 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3669 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3670 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3671 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3672 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3673 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3674 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3676 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3677 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3678 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3679 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3680 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3681 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3682 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3683 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3684 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3685 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3686 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3687 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3688 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3689 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3690 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3691 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3699 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3700 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3701 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3702 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3703 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3704 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3705 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3706 VM_SV_WritePicture, // #501
3708 VM_whichpack, // #503 string(string) whichpack = #503;
3715 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3716 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3717 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3718 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)
3719 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3720 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3721 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3722 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3723 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3724 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3734 VM_loadfromdata, // #529
3735 VM_loadfromfile, // #530
3736 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3738 VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
3739 VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
3740 VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
3741 VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
3742 VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
3743 VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
3745 VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
3746 VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
3747 VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
3810 VM_callfunction, // #605
3811 VM_writetofile, // #606
3812 VM_isfunction, // #607
3818 VM_parseentitydata, // #613
3829 VM_SV_getextresponse, // #624 string getextresponse(void)
3832 VM_sprintf, // #627 string sprintf(string format, ...)
3833 VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
3834 VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
3844 VM_digest_hex, // #639
3847 VM_coverage, // #642
3851 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
3853 void SVVM_init_cmd(prvm_prog_t *prog)
3858 void SVVM_reset_cmd(prvm_prog_t *prog)
3860 World_End(&sv.world);
3862 if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
3864 func_t s = PRVM_serverfunction(SV_Shutdown);
3865 PRVM_serverglobalfloat(time) = sv.time;
3866 PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
3867 prog->ExecuteProgram(prog, s,"SV_Shutdown() required");