6 //============================================================================
11 char *vm_sv_extensions =
16 "DP_CON_ALIASPARAMETERS "
22 "DP_CSQC_ENTITYNOCULL "
23 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
24 "DP_CSQC_MULTIFRAME_INTERPOLATION "
25 "DP_CSQC_SPAWNPARTICLE "
37 "DP_EF_RESTARTANIM_BIT "
42 "DP_ENT_CUSTOMCOLORMAP "
43 "DP_ENT_EXTERIORMODELTOCLIENT "
46 "DP_ENT_LOWPRECISION "
50 "DP_GFX_EXTERNALTEXTURES "
51 "DP_GFX_EXTERNALTEXTURES_PERMAP "
53 "DP_GFX_MODEL_INTERPOLATION "
54 "DP_GFX_QUAKE3MODELTAGS "
58 "DP_HALFLIFE_MAP_CVAR "
61 "DP_LIGHTSTYLE_STATICVALUE "
65 "DP_MOVETYPEBOUNCEMISSILE "
68 "DP_QC_ASINACOSATANATAN2TAN "
74 "DP_QC_CVAR_DEFSTRING "
75 "DP_QC_CVAR_DESCRIPTION "
82 "DP_QC_EXTRESPONSEPACKET "
84 "DP_QC_FINDCHAINFLAGS "
85 "DP_QC_FINDCHAINFLOAT "
86 "DP_QC_FINDCHAIN_TOFIELD "
92 "DP_QC_GETSURFACEPOINTATTRIBUTE "
94 "DP_QC_GETTAGINFO_BONEPROPERTIES "
96 "DP_QC_GETTIME_CDTRACK "
99 "DP_QC_MULTIPLETEMPSTRINGS "
100 "DP_QC_NUM_FOR_EDICT "
102 "DP_QC_SINCOSSQRTPOW "
105 "DP_QC_STRINGBUFFERS "
106 "DP_QC_STRINGBUFFERS_CVARLIST "
107 "DP_QC_STRINGCOLORFUNCTIONS "
108 "DP_QC_STRING_CASE_FUNCTIONS "
110 "DP_QC_TOKENIZEBYSEPARATOR "
111 "DP_QC_TOKENIZE_CONSOLE "
115 "DP_QC_TRACE_MOVETYPE_HITMODEL "
116 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
117 "DP_QC_UNLIMITEDTEMPSTRINGS "
120 "DP_QC_VECTOANGLES_WITH_ROLL "
121 "DP_QC_VECTORVECTORS "
128 "DP_SKELETONOBJECTS "
129 "DP_SND_DIRECTIONLESSATTNNONE "
137 "DP_SV_BOUNCEFACTOR "
138 "DP_SV_CLIENTCOLORS "
141 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
142 "DP_SV_DRAWONLYTOCLIENT "
145 "DP_SV_ENTITYCONTENTSTRANSITION "
146 "DP_SV_MODELFLAGS_AS_EFFECTS "
147 "DP_SV_MOVETYPESTEP_LANDEVENT "
149 "DP_SV_NODRAWTOCLIENT "
150 "DP_SV_ONENTITYNOSPAWNFUNCTION "
151 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
153 "DP_SV_PING_PACKETLOSS "
154 "DP_SV_PLAYERPHYSICS "
155 "DP_SV_POINTPARTICLES "
157 "DP_SV_PRECACHEANYTIME "
161 "DP_SV_ROTATINGBMODEL "
165 "DP_SV_SPAWNFUNC_PREFIX "
166 "DP_SV_WRITEPICTURE "
167 "DP_SV_WRITEUNTERMINATEDSTRING "
171 "DP_TE_EXPLOSIONRGB "
173 "DP_TE_PARTICLECUBE "
174 "DP_TE_PARTICLERAIN "
175 "DP_TE_PARTICLESNOW "
177 "DP_TE_QUADEFFECTS1 "
180 "DP_TE_STANDARDEFFECTBUILTINS "
181 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
185 "FTE_CSQC_SKELETONOBJECTS "
188 "KRIMZON_SV_PARSECLIENTCOMMAND "
191 "NEXUIZ_PLAYERMODEL "
193 "PRYDON_CLIENTCURSOR "
194 "TENEBRAE_GFX_DLIGHTS "
197 //"EXT_CSQC " // not ready yet
204 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.
206 setorigin (entity, origin)
209 static void VM_SV_setorigin (void)
214 VM_SAFEPARMCOUNT(2, VM_setorigin);
216 e = PRVM_G_EDICT(OFS_PARM0);
217 if (e == prog->edicts)
219 VM_Warning("setorigin: can not modify world entity\n");
222 if (e->priv.server->free)
224 VM_Warning("setorigin: can not modify free entity\n");
227 org = PRVM_G_VECTOR(OFS_PARM1);
228 VectorCopy (org, e->fields.server->origin);
232 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
233 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
237 for (i=0 ; i<3 ; i++)
239 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
241 // set derived values
242 VectorCopy (min, e->fields.server->mins);
243 VectorCopy (max, e->fields.server->maxs);
244 VectorSubtract (max, min, e->fields.server->size);
253 the size box is rotated by the current angle
254 LordHavoc: no it isn't...
256 setsize (entity, minvector, maxvector)
259 static void VM_SV_setsize (void)
264 VM_SAFEPARMCOUNT(3, VM_setsize);
266 e = PRVM_G_EDICT(OFS_PARM0);
267 if (e == prog->edicts)
269 VM_Warning("setsize: can not modify world entity\n");
272 if (e->priv.server->free)
274 VM_Warning("setsize: can not modify free entity\n");
277 min = PRVM_G_VECTOR(OFS_PARM1);
278 max = PRVM_G_VECTOR(OFS_PARM2);
279 SetMinMaxSize (e, min, max, false);
287 setmodel(entity, model)
290 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
291 static void VM_SV_setmodel (void)
297 VM_SAFEPARMCOUNT(2, VM_setmodel);
299 e = PRVM_G_EDICT(OFS_PARM0);
300 if (e == prog->edicts)
302 VM_Warning("setmodel: can not modify world entity\n");
305 if (e->priv.server->free)
307 VM_Warning("setmodel: can not modify free entity\n");
310 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
311 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
312 e->fields.server->modelindex = i;
314 mod = SV_GetModelByIndex(i);
318 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
319 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
321 SetMinMaxSize (e, quakemins, quakemaxs, true);
324 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
331 single print to a specific client
333 sprint(clientent, value)
336 static void VM_SV_sprint (void)
340 char string[VM_STRINGTEMP_LENGTH];
342 VM_VarString(1, string, sizeof(string));
344 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
346 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
347 // LordHavoc: div0 requested that sprintto world operate like print
354 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
356 VM_Warning("tried to centerprint to a non-client\n");
360 client = svs.clients + entnum-1;
361 if (!client->netconnection)
364 MSG_WriteChar(&client->netconnection->message,svc_print);
365 MSG_WriteString(&client->netconnection->message, string);
373 single print to a specific client
375 centerprint(clientent, value)
378 static void VM_SV_centerprint (void)
382 char string[VM_STRINGTEMP_LENGTH];
384 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
386 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
388 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
390 VM_Warning("tried to centerprint to a non-client\n");
394 client = svs.clients + entnum-1;
395 if (!client->netconnection)
398 VM_VarString(1, string, sizeof(string));
399 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
400 MSG_WriteString(&client->netconnection->message, string);
407 particle(origin, color, count)
410 static void VM_SV_particle (void)
416 VM_SAFEPARMCOUNT(4, VM_SV_particle);
418 org = PRVM_G_VECTOR(OFS_PARM0);
419 dir = PRVM_G_VECTOR(OFS_PARM1);
420 color = PRVM_G_FLOAT(OFS_PARM2);
421 count = PRVM_G_FLOAT(OFS_PARM3);
422 SV_StartParticle (org, dir, (int)color, (int)count);
432 static void VM_SV_ambientsound (void)
436 float vol, attenuation;
439 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
441 pos = PRVM_G_VECTOR (OFS_PARM0);
442 samp = PRVM_G_STRING(OFS_PARM1);
443 vol = PRVM_G_FLOAT(OFS_PARM2);
444 attenuation = PRVM_G_FLOAT(OFS_PARM3);
446 // check to see if samp was properly precached
447 soundnum = SV_SoundIndex(samp, 1);
455 // add an svc_spawnambient command to the level signon packet
458 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
460 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
462 MSG_WriteVector(&sv.signon, pos, sv.protocol);
464 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
465 MSG_WriteShort (&sv.signon, soundnum);
467 MSG_WriteByte (&sv.signon, soundnum);
469 MSG_WriteByte (&sv.signon, (int)(vol*255));
470 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
478 Each entity can have eight independant sound sources, like voice,
481 Channel 0 is an auto-allocate channel, the others override anything
482 already running on that entity/channel pair.
484 An attenuation of 0 will play full volume everywhere in the level.
485 Larger attenuations will drop off.
489 static void VM_SV_sound (void)
493 prvm_edict_t *entity;
497 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
499 entity = PRVM_G_EDICT(OFS_PARM0);
500 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
501 sample = PRVM_G_STRING(OFS_PARM2);
502 volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
503 attenuation = PRVM_G_FLOAT(OFS_PARM4);
506 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
510 if (volume < 0 || volume > 255)
512 VM_Warning("SV_StartSound: volume must be in range 0-1\n");
516 if (attenuation < 0 || attenuation > 4)
518 VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
522 if (channel < 0 || channel > 7)
524 VM_Warning("SV_StartSound: channel must be in range 0-7\n");
528 SV_StartSound (entity, channel, sample, volume, attenuation);
535 Follows the same logic as VM_SV_sound, except instead of
536 an entity, an origin for the sound is provided, and channel
537 is omitted (since no entity is being tracked).
541 static void VM_SV_pointsound(void)
548 VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
550 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
551 sample = PRVM_G_STRING(OFS_PARM1);
552 volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
553 attenuation = PRVM_G_FLOAT(OFS_PARM3);
555 if (volume < 0 || volume > 255)
557 VM_Warning("SV_StartPointSound: volume must be in range 0-1\n");
561 if (attenuation < 0 || attenuation > 4)
563 VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
567 SV_StartPointSound (org, sample, volume, attenuation);
574 Used for use tracing and shot targeting
575 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
576 if the tryents flag is set.
578 traceline (vector1, vector2, movetype, ignore)
581 static void VM_SV_traceline (void)
588 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
590 prog->xfunction->builtinsprofile += 30;
592 v1 = PRVM_G_VECTOR(OFS_PARM0);
593 v2 = PRVM_G_VECTOR(OFS_PARM1);
594 move = (int)PRVM_G_FLOAT(OFS_PARM2);
595 ent = PRVM_G_EDICT(OFS_PARM3);
597 if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
598 PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
600 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
602 VM_SetTraceGlobals(&trace);
610 Used for use tracing and shot targeting
611 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
612 if the tryents flag is set.
614 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
617 // LordHavoc: added this for my own use, VERY useful, similar to traceline
618 static void VM_SV_tracebox (void)
620 float *v1, *v2, *m1, *m2;
625 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
627 prog->xfunction->builtinsprofile += 30;
629 v1 = PRVM_G_VECTOR(OFS_PARM0);
630 m1 = PRVM_G_VECTOR(OFS_PARM1);
631 m2 = PRVM_G_VECTOR(OFS_PARM2);
632 v2 = PRVM_G_VECTOR(OFS_PARM3);
633 move = (int)PRVM_G_FLOAT(OFS_PARM4);
634 ent = PRVM_G_EDICT(OFS_PARM5);
636 if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
637 PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_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));
639 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
641 VM_SetTraceGlobals(&trace);
648 Used for use tracing and shot targeting
649 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
650 if the tryents flag is set.
652 traceboxbox (vector1, vector mins, vector maxs, vector2, vector mins2, vector maxs2, tryents)
655 static void VM_SV_traceboxbox (void)
657 float *v1, *v2, *mi1, *mi2, *ma1, *ma2;
662 VM_SAFEPARMCOUNT(8, VM_SV_traceboxbox);
664 prog->xfunction->builtinsprofile += 30;
666 v1 = PRVM_G_VECTOR(OFS_PARM0);
667 mi1 = PRVM_G_VECTOR(OFS_PARM1);
668 ma1 = PRVM_G_VECTOR(OFS_PARM2);
669 v2 = PRVM_G_VECTOR(OFS_PARM3);
670 mi2 = PRVM_G_VECTOR(OFS_PARM4);
671 ma2 = PRVM_G_VECTOR(OFS_PARM5);
672 move = (int)PRVM_G_FLOAT(OFS_PARM6);
673 ent = PRVM_G_EDICT(OFS_PARM7);
675 if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
676 PRVM_ERROR("%s: NAN errors detected in traceboxbox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], mi1[0], mi1[1], mi1[2], ma1[0], ma1[1], ma1[2], v2[0], v2[1], v2[2], mi2[0], mi2[1], mi2[2], ma2[0], ma2[1], ma2[2], move, PRVM_EDICT_TO_PROG(ent));
678 trace = SV_TraceBoxBox(v1, mi1, ma1, v2, mi2, ma2, move, ent, SV_GenericHitSuperContentsMask(ent));
680 VM_SetTraceGlobals(&trace);
683 static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
688 vec3_t original_origin;
689 vec3_t original_velocity;
690 vec3_t original_angles;
691 vec3_t original_avelocity;
695 VectorCopy(tossent->fields.server->origin , original_origin );
696 VectorCopy(tossent->fields.server->velocity , original_velocity );
697 VectorCopy(tossent->fields.server->angles , original_angles );
698 VectorCopy(tossent->fields.server->avelocity, original_avelocity);
700 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
701 if (val != NULL && val->_float != 0)
702 gravity = val->_float;
705 gravity *= sv_gravity.value * 0.025;
707 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
709 SV_CheckVelocity (tossent);
710 tossent->fields.server->velocity[2] -= gravity;
711 VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
712 VectorScale (tossent->fields.server->velocity, 0.05, move);
713 VectorAdd (tossent->fields.server->origin, move, end);
714 trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
715 VectorCopy (trace.endpos, tossent->fields.server->origin);
716 tossent->fields.server->velocity[2] -= gravity;
718 if (trace.fraction < 1)
722 VectorCopy(original_origin , tossent->fields.server->origin );
723 VectorCopy(original_velocity , tossent->fields.server->velocity );
724 VectorCopy(original_angles , tossent->fields.server->angles );
725 VectorCopy(original_avelocity, tossent->fields.server->avelocity);
730 static void VM_SV_tracetoss (void)
734 prvm_edict_t *ignore;
736 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
738 prog->xfunction->builtinsprofile += 600;
740 ent = PRVM_G_EDICT(OFS_PARM0);
741 if (ent == prog->edicts)
743 VM_Warning("tracetoss: can not use world entity\n");
746 ignore = PRVM_G_EDICT(OFS_PARM1);
748 trace = SV_Trace_Toss (ent, ignore);
750 VM_SetTraceGlobals(&trace);
753 //============================================================================
755 static int checkpvsbytes;
756 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
758 static int VM_SV_newcheckclient (int check)
764 // cycle to the next one
766 check = bound(1, check, svs.maxclients);
767 if (check == svs.maxclients)
775 prog->xfunction->builtinsprofile++;
777 if (i == svs.maxclients+1)
779 // look up the client's edict
780 ent = PRVM_EDICT_NUM(i);
781 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
782 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
784 // found a valid client (possibly the same one again)
788 // get the PVS for the entity
789 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
791 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
792 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
801 Returns a client (or object that has a client enemy) that would be a
804 If there is more than one valid option, they are cycled each frame
806 If (self.origin + self.viewofs) is not in the PVS of the current target,
807 it is not returned at all.
812 int c_invis, c_notvis;
813 static void VM_SV_checkclient (void)
815 prvm_edict_t *ent, *self;
818 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
820 // find a new check if on a new frame
821 if (sv.time - sv.lastchecktime >= 0.1)
823 sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
824 sv.lastchecktime = sv.time;
827 // return check if it might be visible
828 ent = PRVM_EDICT_NUM(sv.lastcheck);
829 if (ent->priv.server->free || ent->fields.server->health <= 0)
831 VM_RETURN_EDICT(prog->edicts);
835 // if current entity can't possibly see the check entity, return 0
836 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
837 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
838 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
841 VM_RETURN_EDICT(prog->edicts);
845 // might be able to see it
847 VM_RETURN_EDICT(ent);
850 //============================================================================
856 Checks if an entity is in a point's PVS.
857 Should be fast but can be inexact.
859 float checkpvs(vector viewpos, entity viewee) = #240;
862 static void VM_SV_checkpvs (void)
865 prvm_edict_t *viewee;
870 unsigned char fatpvs[MAX_MAP_LEAFS/8];
873 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
874 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
875 viewee = PRVM_G_EDICT(OFS_PARM1);
877 if(viewee->priv.server->free)
879 VM_Warning("checkpvs: can not check free entity\n");
880 PRVM_G_FLOAT(OFS_RETURN) = 4;
885 if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
887 // no PVS support on this worldmodel... darn
888 PRVM_G_FLOAT(OFS_RETURN) = 3;
891 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
894 // viewpos isn't in any PVS... darn
895 PRVM_G_FLOAT(OFS_RETURN) = 2;
898 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
900 // using fat PVS like FTEQW does (slow)
901 if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
903 // no PVS support on this worldmodel... darn
904 PRVM_G_FLOAT(OFS_RETURN) = 3;
907 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
910 // viewpos isn't in any PVS... darn
911 PRVM_G_FLOAT(OFS_RETURN) = 2;
914 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
923 Sends text over to the client's execution buffer
925 stuffcmd (clientent, value, ...)
928 static void VM_SV_stuffcmd (void)
932 char string[VM_STRINGTEMP_LENGTH];
934 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
936 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
937 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
939 VM_Warning("Can't stuffcmd to a non-client\n");
943 VM_VarString(1, string, sizeof(string));
946 host_client = svs.clients + entnum-1;
947 Host_ClientCommands ("%s", string);
955 Returns a chain of entities that have origins within a spherical area
957 findradius (origin, radius)
960 static void VM_SV_findradius (void)
962 prvm_edict_t *ent, *chain;
963 vec_t radius, radius2;
964 vec3_t org, eorg, mins, maxs;
967 static prvm_edict_t *touchedicts[MAX_EDICTS];
970 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
973 chainfield = PRVM_G_INT(OFS_PARM2);
975 chainfield = prog->fieldoffsets.chain;
977 PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
979 chain = (prvm_edict_t *)prog->edicts;
981 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
982 radius = PRVM_G_FLOAT(OFS_PARM1);
983 radius2 = radius * radius;
985 mins[0] = org[0] - (radius + 1);
986 mins[1] = org[1] - (radius + 1);
987 mins[2] = org[2] - (radius + 1);
988 maxs[0] = org[0] + (radius + 1);
989 maxs[1] = org[1] + (radius + 1);
990 maxs[2] = org[2] + (radius + 1);
991 numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
992 if (numtouchedicts > MAX_EDICTS)
994 // this never happens
995 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
996 numtouchedicts = MAX_EDICTS;
998 for (i = 0;i < numtouchedicts;i++)
1000 ent = touchedicts[i];
1001 prog->xfunction->builtinsprofile++;
1002 // Quake did not return non-solid entities but darkplaces does
1003 // (note: this is the reason you can't blow up fallen zombies)
1004 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1006 // LordHavoc: compare against bounding box rather than center so it
1007 // doesn't miss large objects, and use DotProduct instead of Length
1008 // for a major speedup
1009 VectorSubtract(org, ent->fields.server->origin, eorg);
1010 if (sv_gameplayfix_findradiusdistancetobox.integer)
1012 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
1013 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
1014 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
1017 VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
1018 if (DotProduct(eorg, eorg) < radius2)
1020 PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
1025 VM_RETURN_EDICT(chain);
1028 static void VM_SV_precache_sound (void)
1030 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
1031 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1034 static void VM_SV_precache_model (void)
1036 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
1037 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1038 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1045 float(float yaw, float dist[, settrace]) walkmove
1048 static void VM_SV_walkmove (void)
1057 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1059 // assume failure if it returns early
1060 PRVM_G_FLOAT(OFS_RETURN) = 0;
1062 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1063 if (ent == prog->edicts)
1065 VM_Warning("walkmove: can not modify world entity\n");
1068 if (ent->priv.server->free)
1070 VM_Warning("walkmove: can not modify free entity\n");
1073 yaw = PRVM_G_FLOAT(OFS_PARM0);
1074 dist = PRVM_G_FLOAT(OFS_PARM1);
1075 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1077 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1080 yaw = yaw*M_PI*2 / 360;
1082 move[0] = cos(yaw)*dist;
1083 move[1] = sin(yaw)*dist;
1086 // save program state, because SV_movestep may call other progs
1087 oldf = prog->xfunction;
1088 oldself = prog->globals.server->self;
1090 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1093 // restore program state
1094 prog->xfunction = oldf;
1095 prog->globals.server->self = oldself;
1105 static void VM_SV_droptofloor (void)
1111 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1113 // assume failure if it returns early
1114 PRVM_G_FLOAT(OFS_RETURN) = 0;
1116 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1117 if (ent == prog->edicts)
1119 VM_Warning("droptofloor: can not modify world entity\n");
1122 if (ent->priv.server->free)
1124 VM_Warning("droptofloor: can not modify free entity\n");
1128 VectorCopy (ent->fields.server->origin, end);
1131 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1132 SV_UnstickEntity(ent);
1134 trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1135 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1138 VectorSet(offset, 0.5f * (ent->fields.server->mins[0] + ent->fields.server->maxs[0]), 0.5f * (ent->fields.server->mins[1] + ent->fields.server->maxs[1]), ent->fields.server->mins[2]);
1139 VectorAdd(ent->fields.server->origin, offset, org);
1140 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1141 VectorSubtract(trace.endpos, offset, trace.endpos);
1142 if (trace.startsolid)
1144 Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
1145 SV_UnstickEntity(ent);
1147 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1148 ent->fields.server->groundentity = 0;
1149 PRVM_G_FLOAT(OFS_RETURN) = 1;
1151 else if (trace.fraction < 1)
1153 Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
1154 VectorCopy (trace.endpos, ent->fields.server->origin);
1155 SV_UnstickEntity(ent);
1157 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1158 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1159 PRVM_G_FLOAT(OFS_RETURN) = 1;
1160 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1161 ent->priv.server->suspendedinairflag = true;
1166 if (trace.fraction != 1)
1168 if (trace.fraction < 1)
1169 VectorCopy (trace.endpos, ent->fields.server->origin);
1171 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1172 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1173 PRVM_G_FLOAT(OFS_RETURN) = 1;
1174 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1175 ent->priv.server->suspendedinairflag = true;
1184 void(float style, string value) lightstyle
1187 static void VM_SV_lightstyle (void)
1194 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1196 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1197 val = PRVM_G_STRING(OFS_PARM1);
1199 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1200 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
1203 // change the string in sv
1204 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1206 // send message to all clients on this server
1207 if (sv.state != ss_active)
1210 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1212 if (client->active && client->netconnection)
1214 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1215 MSG_WriteChar (&client->netconnection->message,style);
1216 MSG_WriteString (&client->netconnection->message, val);
1226 static void VM_SV_checkbottom (void)
1228 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1229 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1237 static void VM_SV_pointcontents (void)
1239 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1240 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1247 Pick a vector for the player to shoot along
1248 vector aim(entity, missilespeed)
1251 static void VM_SV_aim (void)
1253 prvm_edict_t *ent, *check, *bestent;
1254 vec3_t start, dir, end, bestdir;
1257 float dist, bestdist;
1260 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1262 // assume failure if it returns early
1263 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1264 // if sv_aim is so high it can't possibly accept anything, skip out early
1265 if (sv_aim.value >= 1)
1268 ent = PRVM_G_EDICT(OFS_PARM0);
1269 if (ent == prog->edicts)
1271 VM_Warning("aim: can not use world entity\n");
1274 if (ent->priv.server->free)
1276 VM_Warning("aim: can not use free entity\n");
1279 speed = PRVM_G_FLOAT(OFS_PARM1);
1281 VectorCopy (ent->fields.server->origin, start);
1284 // try sending a trace straight
1285 VectorCopy (prog->globals.server->v_forward, dir);
1286 VectorMA (start, 2048, dir, end);
1287 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1288 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1289 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1291 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1296 // try all possible entities
1297 VectorCopy (dir, bestdir);
1298 bestdist = sv_aim.value;
1301 check = PRVM_NEXT_EDICT(prog->edicts);
1302 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1304 prog->xfunction->builtinsprofile++;
1305 if (check->fields.server->takedamage != DAMAGE_AIM)
1309 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1310 continue; // don't aim at teammate
1311 for (j=0 ; j<3 ; j++)
1312 end[j] = check->fields.server->origin[j]
1313 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1314 VectorSubtract (end, start, dir);
1315 VectorNormalize (dir);
1316 dist = DotProduct (dir, prog->globals.server->v_forward);
1317 if (dist < bestdist)
1318 continue; // to far to turn
1319 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1320 if (tr.ent == check)
1321 { // can shoot at this one
1329 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1330 dist = DotProduct (dir, prog->globals.server->v_forward);
1331 VectorScale (prog->globals.server->v_forward, dist, end);
1333 VectorNormalize (end);
1334 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1338 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1343 ===============================================================================
1347 ===============================================================================
1350 #define MSG_BROADCAST 0 // unreliable to all
1351 #define MSG_ONE 1 // reliable to one (msg_entity)
1352 #define MSG_ALL 2 // reliable to all
1353 #define MSG_INIT 3 // write to the init string
1354 #define MSG_ENTITY 5
1356 sizebuf_t *WriteDest (void)
1362 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1366 return &sv.datagram;
1369 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1370 entnum = PRVM_NUM_FOR_EDICT(ent);
1371 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1373 VM_Warning ("WriteDest: tried to write to non-client\n");
1374 return &sv.reliable_datagram;
1377 return &svs.clients[entnum-1].netconnection->message;
1380 VM_Warning ("WriteDest: bad destination\n");
1382 return &sv.reliable_datagram;
1388 return sv.writeentitiestoclient_msg;
1394 static void VM_SV_WriteByte (void)
1396 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1397 MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1400 static void VM_SV_WriteChar (void)
1402 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1403 MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1406 static void VM_SV_WriteShort (void)
1408 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1409 MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1412 static void VM_SV_WriteLong (void)
1414 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1415 MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1418 static void VM_SV_WriteAngle (void)
1420 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1421 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1424 static void VM_SV_WriteCoord (void)
1426 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1427 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1430 static void VM_SV_WriteString (void)
1432 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1433 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1436 static void VM_SV_WriteUnterminatedString (void)
1438 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1439 MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1443 static void VM_SV_WriteEntity (void)
1445 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1446 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1449 // writes a picture as at most size bytes of data
1451 // IMGNAME \0 SIZE(short) IMGDATA
1452 // if failed to read/compress:
1454 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1455 static void VM_SV_WritePicture (void)
1457 const char *imgname;
1461 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1463 imgname = PRVM_G_STRING(OFS_PARM1);
1464 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1468 MSG_WriteString(WriteDest(), imgname);
1469 if(Image_Compress(imgname, size, &buf, &size))
1472 MSG_WriteShort(WriteDest(), size);
1473 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1478 MSG_WriteShort(WriteDest(), 0);
1482 //////////////////////////////////////////////////////////
1484 static void VM_SV_makestatic (void)
1489 // allow 0 parameters due to an id1 qc bug in which this function is used
1490 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1491 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1493 if (prog->argc >= 1)
1494 ent = PRVM_G_EDICT(OFS_PARM0);
1496 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1497 if (ent == prog->edicts)
1499 VM_Warning("makestatic: can not modify world entity\n");
1502 if (ent->priv.server->free)
1504 VM_Warning("makestatic: can not modify free entity\n");
1509 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1514 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1515 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1516 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1518 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1520 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1521 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1522 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1526 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1527 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1528 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1531 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1532 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1533 for (i=0 ; i<3 ; i++)
1535 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1536 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1539 // throw the entity away now
1543 //=============================================================================
1550 static void VM_SV_setspawnparms (void)
1556 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1558 ent = PRVM_G_EDICT(OFS_PARM0);
1559 i = PRVM_NUM_FOR_EDICT(ent);
1560 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1562 Con_Print("tried to setspawnparms on a non-client\n");
1566 // copy spawn parms out of the client_t
1567 client = svs.clients + i-1;
1568 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1569 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1576 Returns a color vector indicating the lighting at the requested point.
1578 (Internal Operation note: actually measures the light beneath the point, just like
1579 the model lighting on the client)
1584 static void VM_SV_getlight (void)
1586 vec3_t ambientcolor, diffusecolor, diffusenormal;
1588 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1589 p = PRVM_G_VECTOR(OFS_PARM0);
1590 VectorClear(ambientcolor);
1591 VectorClear(diffusecolor);
1592 VectorClear(diffusenormal);
1593 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1594 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1595 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1600 unsigned char type; // 1/2/8 or other value if isn't used
1604 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1605 static int vm_customstats_last;
1607 void VM_CustomStats_Clear (void)
1611 Z_Free(vm_customstats);
1612 vm_customstats = NULL;
1613 vm_customstats_last = -1;
1617 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1625 for(i=0; i<vm_customstats_last+1 ;i++)
1627 if(!vm_customstats[i].type)
1629 switch(vm_customstats[i].type)
1631 //string as 16 bytes
1634 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1635 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1636 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1637 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1638 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1640 //float field sent as-is
1642 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1644 //integer value of float field
1646 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1654 // void(float index, float type, .void field) SV_AddStat = #232;
1655 // Set up an auto-sent player stat.
1656 // Client's get thier own fields sent to them. Index may not be less than 32.
1657 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1658 // 1: string (4 stats carrying a total of 16 charactures)
1659 // 2: float (one stat, float converted to an integer for transportation)
1660 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1661 static void VM_SV_AddStat (void)
1666 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1670 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1673 VM_Warning("PF_SV_AddStat: not enough memory\n");
1677 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1678 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1679 off = PRVM_G_INT (OFS_PARM2);
1684 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1687 if(i >= (MAX_CL_STATS-32))
1689 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1692 if(i > (MAX_CL_STATS-32-4) && type == 1)
1694 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1697 vm_customstats[i].type = type;
1698 vm_customstats[i].fieldoffset = off;
1699 if(vm_customstats_last < i)
1700 vm_customstats_last = i;
1707 copies data from one entity to another
1709 copyentity(src, dst)
1712 static void VM_SV_copyentity (void)
1714 prvm_edict_t *in, *out;
1715 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1716 in = PRVM_G_EDICT(OFS_PARM0);
1717 if (in == prog->edicts)
1719 VM_Warning("copyentity: can not read world entity\n");
1722 if (in->priv.server->free)
1724 VM_Warning("copyentity: can not read free entity\n");
1727 out = PRVM_G_EDICT(OFS_PARM1);
1728 if (out == prog->edicts)
1730 VM_Warning("copyentity: can not modify world entity\n");
1733 if (out->priv.server->free)
1735 VM_Warning("copyentity: can not modify free entity\n");
1738 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1747 sets the color of a client and broadcasts the update to all connected clients
1749 setcolor(clientent, value)
1752 static void VM_SV_setcolor (void)
1758 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1759 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1760 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1762 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1764 Con_Print("tried to setcolor a non-client\n");
1768 client = svs.clients + entnum-1;
1771 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1773 client->edict->fields.server->team = (i & 15) + 1;
1776 if (client->old_colors != client->colors)
1778 client->old_colors = client->colors;
1779 // send notification to all clients
1780 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1781 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1782 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1790 effect(origin, modelname, startframe, framecount, framerate)
1793 static void VM_SV_effect (void)
1797 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1798 s = PRVM_G_STRING(OFS_PARM1);
1801 VM_Warning("effect: no model specified\n");
1805 i = SV_ModelIndex(s, 1);
1808 VM_Warning("effect: model not precached\n");
1812 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1814 VM_Warning("effect: framecount < 1\n");
1818 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1820 VM_Warning("effect: framerate < 1\n");
1824 SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
1827 static void VM_SV_te_blood (void)
1829 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1830 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1832 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1833 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1835 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1836 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1837 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1839 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1840 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1841 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1843 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1844 SV_FlushBroadcastMessages();
1847 static void VM_SV_te_bloodshower (void)
1849 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1850 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1852 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1853 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1855 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1856 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1857 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1859 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1860 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1861 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1863 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1865 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1866 SV_FlushBroadcastMessages();
1869 static void VM_SV_te_explosionrgb (void)
1871 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1872 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1873 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1875 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1876 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1877 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1879 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1880 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1881 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1882 SV_FlushBroadcastMessages();
1885 static void VM_SV_te_particlecube (void)
1887 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1888 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1890 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1891 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1893 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1894 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1895 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1897 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1898 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1899 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1901 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1902 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1903 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1905 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1907 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1908 // gravity true/false
1909 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1912 SV_FlushBroadcastMessages();
1915 static void VM_SV_te_particlerain (void)
1917 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1918 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1920 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1921 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1923 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1924 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1925 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1927 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1928 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1929 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1931 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1932 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1933 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1935 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1937 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1938 SV_FlushBroadcastMessages();
1941 static void VM_SV_te_particlesnow (void)
1943 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1944 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1946 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1947 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1949 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1950 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1951 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1953 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1954 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1955 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1957 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1958 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1959 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1961 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1963 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1964 SV_FlushBroadcastMessages();
1967 static void VM_SV_te_spark (void)
1969 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1970 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1972 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1973 MSG_WriteByte(&sv.datagram, TE_SPARK);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1976 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1977 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1979 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1980 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1981 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1983 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1984 SV_FlushBroadcastMessages();
1987 static void VM_SV_te_gunshotquad (void)
1989 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1990 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1991 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1993 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1994 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1995 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1996 SV_FlushBroadcastMessages();
1999 static void VM_SV_te_spikequad (void)
2001 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
2002 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2003 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2005 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2006 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2007 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2008 SV_FlushBroadcastMessages();
2011 static void VM_SV_te_superspikequad (void)
2013 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
2014 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2015 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2017 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2018 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2019 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2020 SV_FlushBroadcastMessages();
2023 static void VM_SV_te_explosionquad (void)
2025 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2026 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2027 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2029 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2030 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2031 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2032 SV_FlushBroadcastMessages();
2035 static void VM_SV_te_smallflash (void)
2037 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2038 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2039 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2041 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2042 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2043 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2044 SV_FlushBroadcastMessages();
2047 static void VM_SV_te_customflash (void)
2049 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2050 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2052 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2053 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2055 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2056 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2057 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2059 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2061 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2063 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2064 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2065 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2066 SV_FlushBroadcastMessages();
2069 static void VM_SV_te_gunshot (void)
2071 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2072 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2073 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2075 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2076 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2077 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2078 SV_FlushBroadcastMessages();
2081 static void VM_SV_te_spike (void)
2083 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2084 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2085 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2087 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2088 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2089 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2090 SV_FlushBroadcastMessages();
2093 static void VM_SV_te_superspike (void)
2095 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2096 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2097 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2099 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2100 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2101 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2102 SV_FlushBroadcastMessages();
2105 static void VM_SV_te_explosion (void)
2107 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2108 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2109 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2111 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2112 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2113 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2114 SV_FlushBroadcastMessages();
2117 static void VM_SV_te_tarexplosion (void)
2119 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2120 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2121 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2123 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2124 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2125 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2126 SV_FlushBroadcastMessages();
2129 static void VM_SV_te_wizspike (void)
2131 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2132 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2133 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2135 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2136 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2137 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2138 SV_FlushBroadcastMessages();
2141 static void VM_SV_te_knightspike (void)
2143 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2144 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2145 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2147 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2148 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2149 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2150 SV_FlushBroadcastMessages();
2153 static void VM_SV_te_lavasplash (void)
2155 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2156 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2157 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2159 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2160 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2161 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2162 SV_FlushBroadcastMessages();
2165 static void VM_SV_te_teleport (void)
2167 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2168 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2169 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2171 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2172 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2173 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2174 SV_FlushBroadcastMessages();
2177 static void VM_SV_te_explosion2 (void)
2179 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2180 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2181 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2185 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2187 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2188 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2189 SV_FlushBroadcastMessages();
2192 static void VM_SV_te_lightning1 (void)
2194 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2195 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2196 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2198 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2200 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2201 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2202 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2204 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2205 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2206 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2207 SV_FlushBroadcastMessages();
2210 static void VM_SV_te_lightning2 (void)
2212 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2213 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2214 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2216 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2218 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2222 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2223 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2224 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2225 SV_FlushBroadcastMessages();
2228 static void VM_SV_te_lightning3 (void)
2230 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2231 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2232 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2234 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2236 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2237 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2238 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2240 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2243 SV_FlushBroadcastMessages();
2246 static void VM_SV_te_beam (void)
2248 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2249 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2250 MSG_WriteByte(&sv.datagram, TE_BEAM);
2252 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2254 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2255 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2256 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2258 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2259 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2260 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2261 SV_FlushBroadcastMessages();
2264 static void VM_SV_te_plasmaburn (void)
2266 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2267 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2268 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2272 SV_FlushBroadcastMessages();
2275 static void VM_SV_te_flamejet (void)
2277 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2278 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2279 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2281 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2282 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2283 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2285 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2287 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2289 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2290 SV_FlushBroadcastMessages();
2293 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2296 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2298 bestdist = 1000000000;
2300 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2302 // clip original point to each triangle of the surface and find the
2303 // triangle that is closest
2304 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2305 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2306 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2307 TriangleNormal(v[0], v[1], v[2], facenormal);
2308 VectorNormalize(facenormal);
2309 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2310 VectorMA(p, offsetdist, facenormal, temp);
2311 for (j = 0, k = 2;j < 3;k = j, j++)
2313 VectorSubtract(v[k], v[j], edgenormal);
2314 CrossProduct(edgenormal, facenormal, sidenormal);
2315 VectorNormalize(sidenormal);
2316 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2318 VectorMA(temp, offsetdist, sidenormal, temp);
2320 dist = VectorDistance2(temp, p);
2321 if (bestdist > dist)
2324 VectorCopy(temp, out);
2329 #define getmodel SV_GetModelFromEdict
2331 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2333 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2335 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2339 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2340 static void VM_SV_getsurfacenumpoints(void)
2343 msurface_t *surface;
2344 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2345 // return 0 if no such surface
2346 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2348 PRVM_G_FLOAT(OFS_RETURN) = 0;
2352 // note: this (incorrectly) assumes it is a simple polygon
2353 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2355 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2356 static void VM_SV_getsurfacepoint(void)
2360 msurface_t *surface;
2362 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2363 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2364 ed = PRVM_G_EDICT(OFS_PARM0);
2365 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2367 // note: this (incorrectly) assumes it is a simple polygon
2368 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2369 if (pointnum < 0 || pointnum >= surface->num_vertices)
2371 // FIXME: implement rotation/scaling
2372 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2374 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2375 // float SPA_POSITION = 0;
2376 // float SPA_S_AXIS = 1;
2377 // float SPA_T_AXIS = 2;
2378 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2379 // float SPA_TEXCOORDS0 = 4;
2380 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2381 // float SPA_LIGHTMAP0_COLOR = 6;
2382 static void VM_SV_getsurfacepointattribute(void)
2386 msurface_t *surface;
2390 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2391 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2392 ed = PRVM_G_EDICT(OFS_PARM0);
2393 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2395 // note: this (incorrectly) assumes it is a simple polygon
2396 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2397 if (pointnum < 0 || pointnum >= surface->num_vertices)
2399 // FIXME: implement rotation/scaling
2400 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2402 switch( attributetype ) {
2403 // float SPA_POSITION = 0;
2405 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2407 // float SPA_S_AXIS = 1;
2409 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2411 // float SPA_T_AXIS = 2;
2413 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2415 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2417 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2419 // float SPA_TEXCOORDS0 = 4;
2421 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2422 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2423 ret[0] = texcoord[0];
2424 ret[1] = texcoord[1];
2428 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2430 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2431 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2432 ret[0] = texcoord[0];
2433 ret[1] = texcoord[1];
2437 // float SPA_LIGHTMAP0_COLOR = 6;
2439 // ignore alpha for now..
2440 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2443 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2447 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2448 static void VM_SV_getsurfacenormal(void)
2451 msurface_t *surface;
2453 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2454 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2455 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2457 // FIXME: implement rotation/scaling
2458 // note: this (incorrectly) assumes it is a simple polygon
2459 // note: this only returns the first triangle, so it doesn't work very
2460 // well for curved surfaces or arbitrary meshes
2461 TriangleNormal((model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 3, (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
2462 VectorNormalize(normal);
2463 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2465 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2466 static void VM_SV_getsurfacetexture(void)
2469 msurface_t *surface;
2470 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2471 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2472 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2474 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2476 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2477 static void VM_SV_getsurfacenearpoint(void)
2479 int surfacenum, best;
2481 vec_t dist, bestdist;
2484 msurface_t *surface;
2486 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2487 PRVM_G_FLOAT(OFS_RETURN) = -1;
2488 ed = PRVM_G_EDICT(OFS_PARM0);
2489 point = PRVM_G_VECTOR(OFS_PARM1);
2491 if (!ed || ed->priv.server->free)
2493 model = getmodel(ed);
2494 if (!model || !model->num_surfaces)
2497 // FIXME: implement rotation/scaling
2498 VectorSubtract(point, ed->fields.server->origin, p);
2500 bestdist = 1000000000;
2501 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2503 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2504 // first see if the nearest point on the surface's box is closer than the previous match
2505 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2506 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2507 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2508 dist = VectorLength2(clipped);
2509 if (dist < bestdist)
2511 // it is, check the nearest point on the actual geometry
2512 clippointtosurface(model, surface, p, clipped);
2513 VectorSubtract(clipped, p, clipped);
2514 dist += VectorLength2(clipped);
2515 if (dist < bestdist)
2517 // that's closer too, store it as the best match
2523 PRVM_G_FLOAT(OFS_RETURN) = best;
2525 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2526 static void VM_SV_getsurfaceclippedpoint(void)
2530 msurface_t *surface;
2532 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2533 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2534 ed = PRVM_G_EDICT(OFS_PARM0);
2535 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2537 // FIXME: implement rotation/scaling
2538 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2539 clippointtosurface(model, surface, p, out);
2540 // FIXME: implement rotation/scaling
2541 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2544 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2545 //this function originally written by KrimZon, made shorter by LordHavoc
2546 static void VM_SV_clientcommand (void)
2548 client_t *temp_client;
2550 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2552 //find client for this entity
2553 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2554 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2556 Con_Print("PF_clientcommand: entity is not a client\n");
2560 temp_client = host_client;
2561 host_client = svs.clients + i;
2562 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2563 host_client = temp_client;
2566 //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)
2567 static void VM_SV_setattachment (void)
2569 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2570 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2571 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2574 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2576 if (e == prog->edicts)
2578 VM_Warning("setattachment: can not modify world entity\n");
2581 if (e->priv.server->free)
2583 VM_Warning("setattachment: can not modify free entity\n");
2587 if (tagentity == NULL)
2588 tagentity = prog->edicts;
2590 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2592 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2594 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2597 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2599 model = SV_GetModelFromEdict(tagentity);
2602 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2604 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);
2607 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));
2611 /////////////////////////////////////////
2612 // DP_MD3_TAGINFO extension coded by VorteX
2614 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2618 i = (int)e->fields.server->modelindex;
2619 if (i < 1 || i >= MAX_MODELS)
2622 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2625 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2632 Matrix4x4_CreateIdentity(tag_localmatrix);
2634 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2636 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2647 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2651 float pitchsign = 1;
2654 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2655 if (val && val->_float != 0)
2656 scale = val->_float;
2659 Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + ent->fields.server->view_ofs[2], ent->fields.server->v_angle[0], ent->fields.server->v_angle[1], ent->fields.server->v_angle[2], scale * cl_viewmodel_scale.value);
2662 pitchsign = SV_GetPitchSign(ent);
2663 Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], pitchsign * ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], scale);
2667 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2670 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2672 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2673 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2674 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2675 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2677 *out = identitymatrix;
2681 // Warnings/errors code:
2682 // 0 - normal (everything all-right)
2685 // 3 - null or non-precached model
2686 // 4 - no tags with requested index
2687 // 5 - runaway loop at attachment chain
2688 extern cvar_t cl_bob;
2689 extern cvar_t cl_bobcycle;
2690 extern cvar_t cl_bobup;
2691 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2695 int modelindex, attachloop;
2696 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2699 *out = identitymatrix; // warnings and errors return identical matrix
2701 if (ent == prog->edicts)
2703 if (ent->priv.server->free)
2706 modelindex = (int)ent->fields.server->modelindex;
2707 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2710 model = SV_GetModelByIndex(modelindex);
2712 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2713 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2714 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2716 tagmatrix = identitymatrix;
2717 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2721 if (attachloop >= 256) // prevent runaway looping
2723 // apply transformation by child's tagindex on parent entity and then
2724 // by parent entity itself
2725 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2726 if (ret && attachloop == 0)
2728 SV_GetEntityMatrix(ent, &entitymatrix, false);
2729 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2730 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2731 // next iteration we process the parent entity
2732 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2734 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2735 ent = PRVM_EDICT_NUM(val->edict);
2742 // RENDER_VIEWMODEL magic
2743 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2745 Matrix4x4_Copy(&tagmatrix, out);
2746 ent = PRVM_EDICT_NUM(val->edict);
2748 SV_GetEntityMatrix(ent, &entitymatrix, true);
2749 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2752 // Cl_bob, ported from rendering code
2753 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2756 // LordHavoc: this code is *weird*, but not replacable (I think it
2757 // should be done in QC on the server, but oh well, quake is quake)
2758 // LordHavoc: figured out bobup: the time at which the sin is at 180
2759 // degrees (which allows lengthening or squishing the peak or valley)
2760 cycle = sv.time/cl_bobcycle.value;
2761 cycle -= (int)cycle;
2762 if (cycle < cl_bobup.value)
2763 cycle = sin(M_PI * cycle / cl_bobup.value);
2765 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2766 // bob is proportional to velocity in the xy plane
2767 // (don't count Z, or jumping messes it up)
2768 bob = sqrt(ent->fields.server->velocity[0]*ent->fields.server->velocity[0] + ent->fields.server->velocity[1]*ent->fields.server->velocity[1])*cl_bob.value;
2769 bob = bob*0.3 + bob*0.7*cycle;
2770 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2777 //float(entity ent, string tagname) gettagindex;
2779 static void VM_SV_gettagindex (void)
2782 const char *tag_name;
2785 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2787 ent = PRVM_G_EDICT(OFS_PARM0);
2788 tag_name = PRVM_G_STRING(OFS_PARM1);
2790 if (ent == prog->edicts)
2792 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2795 if (ent->priv.server->free)
2797 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2802 if (!SV_GetModelFromEdict(ent))
2803 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2806 tag_index = SV_GetTagIndex(ent, tag_name);
2808 if(developer_extra.integer)
2809 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2811 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2814 //vector(entity ent, float tagindex) gettaginfo;
2815 static void VM_SV_gettaginfo (void)
2819 matrix4x4_t tag_matrix;
2820 matrix4x4_t tag_localmatrix;
2822 const char *tagname;
2825 vec3_t fo, le, up, trans;
2826 const dp_model_t *model;
2828 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2830 e = PRVM_G_EDICT(OFS_PARM0);
2831 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2833 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2834 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2835 VectorScale(le, -1, prog->globals.server->v_right);
2836 model = SV_GetModelFromEdict(e);
2837 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2838 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2839 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2840 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2841 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2843 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2844 val->_float = parentindex;
2845 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2846 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2847 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2848 VectorCopy(trans, val->vector);
2849 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2850 VectorCopy(fo, val->vector);
2851 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2852 VectorScale(le, -1, val->vector);
2853 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2854 VectorCopy(up, val->vector);
2859 VM_Warning("gettagindex: can't affect world entity\n");
2862 VM_Warning("gettagindex: can't affect free entity\n");
2865 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2868 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2871 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2876 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2877 static void VM_SV_dropclient (void)
2880 client_t *oldhostclient;
2881 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2882 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2883 if (clientnum < 0 || clientnum >= svs.maxclients)
2885 VM_Warning("dropclient: not a client\n");
2888 if (!svs.clients[clientnum].active)
2890 VM_Warning("dropclient: that client slot is not connected\n");
2893 oldhostclient = host_client;
2894 host_client = svs.clients + clientnum;
2895 SV_DropClient(false);
2896 host_client = oldhostclient;
2899 //entity() spawnclient (DP_SV_BOTCLIENT)
2900 static void VM_SV_spawnclient (void)
2904 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2905 prog->xfunction->builtinsprofile += 2;
2907 for (i = 0;i < svs.maxclients;i++)
2909 if (!svs.clients[i].active)
2911 prog->xfunction->builtinsprofile += 100;
2912 SV_ConnectClient (i, NULL);
2913 // this has to be set or else ClientDisconnect won't be called
2914 // we assume the qc will call ClientConnect...
2915 svs.clients[i].clientconnectcalled = true;
2916 ed = PRVM_EDICT_NUM(i + 1);
2920 VM_RETURN_EDICT(ed);
2923 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2924 static void VM_SV_clienttype (void)
2927 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2928 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2929 if (clientnum < 0 || clientnum >= svs.maxclients)
2930 PRVM_G_FLOAT(OFS_RETURN) = 3;
2931 else if (!svs.clients[clientnum].active)
2932 PRVM_G_FLOAT(OFS_RETURN) = 0;
2933 else if (svs.clients[clientnum].netconnection)
2934 PRVM_G_FLOAT(OFS_RETURN) = 1;
2936 PRVM_G_FLOAT(OFS_RETURN) = 2;
2943 string(string key) serverkey
2946 void VM_SV_serverkey(void)
2948 char string[VM_STRINGTEMP_LENGTH];
2949 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2950 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2951 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2954 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2955 static void VM_SV_setmodelindex (void)
2960 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2962 e = PRVM_G_EDICT(OFS_PARM0);
2963 if (e == prog->edicts)
2965 VM_Warning("setmodelindex: can not modify world entity\n");
2968 if (e->priv.server->free)
2970 VM_Warning("setmodelindex: can not modify free entity\n");
2973 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2974 if (i <= 0 || i >= MAX_MODELS)
2976 VM_Warning("setmodelindex: invalid modelindex\n");
2979 if (!sv.model_precache[i][0])
2981 VM_Warning("setmodelindex: model not precached\n");
2985 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2986 e->fields.server->modelindex = i;
2988 mod = SV_GetModelByIndex(i);
2992 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2993 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2995 SetMinMaxSize (e, quakemins, quakemaxs, true);
2998 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
3001 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3002 static void VM_SV_modelnameforindex (void)
3005 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
3007 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
3009 i = (int)PRVM_G_FLOAT(OFS_PARM0);
3010 if (i <= 0 || i >= MAX_MODELS)
3012 VM_Warning("modelnameforindex: invalid modelindex\n");
3015 if (!sv.model_precache[i][0])
3017 VM_Warning("modelnameforindex: model not precached\n");
3021 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
3024 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
3025 static void VM_SV_particleeffectnum (void)
3028 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
3029 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
3032 PRVM_G_FLOAT(OFS_RETURN) = i;
3035 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3036 static void VM_SV_trailparticles (void)
3038 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
3040 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3043 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3044 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3045 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3046 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3047 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3048 SV_FlushBroadcastMessages();
3051 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3052 static void VM_SV_pointparticles (void)
3054 int effectnum, count;
3056 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3058 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3061 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3062 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3063 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3064 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3065 if (count == 1 && !VectorLength2(vel))
3068 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3069 MSG_WriteShort(&sv.datagram, effectnum);
3070 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3074 // 1+2+12+12+2=29 bytes
3075 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3076 MSG_WriteShort(&sv.datagram, effectnum);
3077 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3078 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3079 MSG_WriteShort(&sv.datagram, count);
3082 SV_FlushBroadcastMessages();
3085 //PF_setpause, // void(float pause) setpause = #531;
3086 static void VM_SV_setpause(void) {
3088 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3089 if (pauseValue != 0) { //pause the game
3091 sv.pausedstart = Sys_DoubleTime();
3092 } else { //disable pause, in case it was enabled
3093 if (sv.paused != 0) {
3098 // send notification to all clients
3099 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3100 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3103 // #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.
3104 static void VM_SV_skel_create(void)
3106 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3107 dp_model_t *model = SV_GetModelByIndex(modelindex);
3108 skeleton_t *skeleton;
3110 PRVM_G_FLOAT(OFS_RETURN) = 0;
3111 if (!model || !model->num_bones)
3113 for (i = 0;i < MAX_EDICTS;i++)
3114 if (!prog->skeletons[i])
3116 if (i == MAX_EDICTS)
3118 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3119 skeleton->model = model;
3120 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3121 // initialize to identity matrices
3122 for (i = 0;i < skeleton->model->num_bones;i++)
3123 skeleton->relativetransforms[i] = identitymatrix;
3124 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3127 // #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
3128 static void VM_SV_skel_build(void)
3130 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3131 skeleton_t *skeleton;
3132 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3133 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3134 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3135 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3136 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3137 dp_model_t *model = SV_GetModelByIndex(modelindex);
3142 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3143 frameblend_t frameblend[MAX_FRAMEBLENDS];
3144 matrix4x4_t blendedmatrix;
3146 PRVM_G_FLOAT(OFS_RETURN) = 0;
3147 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3149 firstbone = max(0, firstbone);
3150 lastbone = min(lastbone, model->num_bones - 1);
3151 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3152 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3153 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3154 blendfrac = 1.0f - retainfrac;
3155 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3156 frameblend[numblends].lerp *= blendfrac;
3157 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3159 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3160 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3161 for (blendindex = 0;blendindex < numblends;blendindex++)
3163 Matrix4x4_FromBonePose6s(&matrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3164 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3166 skeleton->relativetransforms[bonenum] = blendedmatrix;
3168 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3171 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3172 static void VM_SV_skel_get_numbones(void)
3174 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3175 skeleton_t *skeleton;
3176 PRVM_G_FLOAT(OFS_RETURN) = 0;
3177 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3179 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3182 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3183 static void VM_SV_skel_get_bonename(void)
3185 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3186 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3187 skeleton_t *skeleton;
3188 PRVM_G_INT(OFS_RETURN) = 0;
3189 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3191 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3193 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3196 // #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)
3197 static void VM_SV_skel_get_boneparent(void)
3199 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3200 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3201 skeleton_t *skeleton;
3202 PRVM_G_FLOAT(OFS_RETURN) = 0;
3203 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3205 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3207 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3210 // #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
3211 static void VM_SV_skel_find_bone(void)
3213 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3214 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3215 skeleton_t *skeleton;
3216 PRVM_G_FLOAT(OFS_RETURN) = 0;
3217 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3219 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3222 // #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)
3223 static void VM_SV_skel_get_bonerel(void)
3225 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3226 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3227 skeleton_t *skeleton;
3229 vec3_t forward, left, up, origin;
3230 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3231 VectorClear(prog->globals.client->v_forward);
3232 VectorClear(prog->globals.client->v_right);
3233 VectorClear(prog->globals.client->v_up);
3234 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3236 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3238 matrix = skeleton->relativetransforms[bonenum];
3239 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3240 VectorCopy(forward, prog->globals.client->v_forward);
3241 VectorNegate(left, prog->globals.client->v_right);
3242 VectorCopy(up, prog->globals.client->v_up);
3243 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3246 // #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)
3247 static void VM_SV_skel_get_boneabs(void)
3249 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3250 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3251 skeleton_t *skeleton;
3254 vec3_t forward, left, up, origin;
3255 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3256 VectorClear(prog->globals.client->v_forward);
3257 VectorClear(prog->globals.client->v_right);
3258 VectorClear(prog->globals.client->v_up);
3259 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3261 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3263 matrix = skeleton->relativetransforms[bonenum];
3264 // convert to absolute
3265 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3268 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3270 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3271 VectorCopy(forward, prog->globals.client->v_forward);
3272 VectorNegate(left, prog->globals.client->v_right);
3273 VectorCopy(up, prog->globals.client->v_up);
3274 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3277 // #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)
3278 static void VM_SV_skel_set_bone(void)
3280 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3281 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3282 vec3_t forward, left, up, origin;
3283 skeleton_t *skeleton;
3285 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3287 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3289 VectorCopy(prog->globals.client->v_forward, forward);
3290 VectorNegate(prog->globals.client->v_right, left);
3291 VectorCopy(prog->globals.client->v_up, up);
3292 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3293 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3294 skeleton->relativetransforms[bonenum] = matrix;
3297 // #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)
3298 static void VM_SV_skel_mul_bone(void)
3300 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3301 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3302 vec3_t forward, left, up, origin;
3303 skeleton_t *skeleton;
3306 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3308 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3310 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3311 VectorCopy(prog->globals.client->v_forward, forward);
3312 VectorNegate(prog->globals.client->v_right, left);
3313 VectorCopy(prog->globals.client->v_up, up);
3314 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3315 temp = skeleton->relativetransforms[bonenum];
3316 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3319 // #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)
3320 static void VM_SV_skel_mul_bones(void)
3322 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3323 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3324 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3326 vec3_t forward, left, up, origin;
3327 skeleton_t *skeleton;
3330 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3332 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3333 VectorCopy(prog->globals.client->v_forward, forward);
3334 VectorNegate(prog->globals.client->v_right, left);
3335 VectorCopy(prog->globals.client->v_up, up);
3336 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3337 firstbone = max(0, firstbone);
3338 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3339 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3341 temp = skeleton->relativetransforms[bonenum];
3342 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3346 // #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
3347 static void VM_SV_skel_copybones(void)
3349 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3350 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3351 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3352 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3354 skeleton_t *skeletondst;
3355 skeleton_t *skeletonsrc;
3356 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3358 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3360 firstbone = max(0, firstbone);
3361 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3362 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3363 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3364 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3367 // #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)
3368 static void VM_SV_skel_delete(void)
3370 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3371 skeleton_t *skeleton;
3372 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3375 prog->skeletons[skeletonindex] = NULL;
3378 // #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
3379 static void VM_SV_frameforname(void)
3381 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3382 dp_model_t *model = SV_GetModelByIndex(modelindex);
3383 const char *name = PRVM_G_STRING(OFS_PARM1);
3385 PRVM_G_FLOAT(OFS_RETURN) = -1;
3386 if (!model || !model->animscenes)
3388 for (i = 0;i < model->numframes;i++)
3390 if (!strcasecmp(model->animscenes[i].name, name))
3392 PRVM_G_FLOAT(OFS_RETURN) = i;
3398 // #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.
3399 static void VM_SV_frameduration(void)
3401 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3402 dp_model_t *model = SV_GetModelByIndex(modelindex);
3403 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3404 PRVM_G_FLOAT(OFS_RETURN) = 0;
3405 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3407 if (model->animscenes[framenum].framerate)
3408 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3412 prvm_builtin_t vm_sv_builtins[] = {
3413 NULL, // #0 NULL function (not callable) (QUAKE)
3414 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3415 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3416 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3417 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3418 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3419 VM_break, // #6 void() break (QUAKE)
3420 VM_random, // #7 float() random (QUAKE)
3421 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3422 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3423 VM_error, // #10 void(string e) error (QUAKE)
3424 VM_objerror, // #11 void(string e) objerror (QUAKE)
3425 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3426 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3427 VM_spawn, // #14 entity() spawn (QUAKE)
3428 VM_remove, // #15 void(entity e) remove (QUAKE)
3429 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3430 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3431 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3432 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3433 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3434 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3435 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3436 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3437 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3438 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3439 VM_ftos, // #26 string(float f) ftos (QUAKE)
3440 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3441 VM_coredump, // #28 void() coredump (QUAKE)
3442 VM_traceon, // #29 void() traceon (QUAKE)
3443 VM_traceoff, // #30 void() traceoff (QUAKE)
3444 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3445 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3446 NULL, // #33 (QUAKE)
3447 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3448 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3449 VM_rint, // #36 float(float v) rint (QUAKE)
3450 VM_floor, // #37 float(float v) floor (QUAKE)
3451 VM_ceil, // #38 float(float v) ceil (QUAKE)
3452 NULL, // #39 (QUAKE)
3453 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3454 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3455 NULL, // #42 (QUAKE)
3456 VM_fabs, // #43 float(float f) fabs (QUAKE)
3457 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3458 VM_cvar, // #45 float(string s) cvar (QUAKE)
3459 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3460 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3461 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3462 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3463 NULL, // #50 (QUAKE)
3464 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3465 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3466 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3467 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3468 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3469 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3470 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3471 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3472 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3473 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3474 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3475 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3476 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3477 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3478 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3479 NULL, // #66 (QUAKE)
3480 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3481 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3482 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3483 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3484 NULL, // #71 (QUAKE)
3485 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3486 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3487 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3488 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3489 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3490 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3491 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3492 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3493 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3494 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3495 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3496 NULL, // #83 (QUAKE)
3497 NULL, // #84 (QUAKE)
3498 NULL, // #85 (QUAKE)
3499 NULL, // #86 (QUAKE)
3500 NULL, // #87 (QUAKE)
3501 NULL, // #88 (QUAKE)
3502 NULL, // #89 (QUAKE)
3503 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3504 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3505 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3506 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3507 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3508 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3509 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3510 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3511 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3512 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3513 // FrikaC and Telejano range #100-#199
3524 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3525 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3526 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3527 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3528 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3529 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3530 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3531 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3532 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3533 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3614 // FTEQW range #200-#299
3633 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3636 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3637 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3638 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3639 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3640 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3641 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3642 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3643 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3644 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3645 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3647 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3655 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3678 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.
3679 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
3680 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3681 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3682 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)
3683 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
3684 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)
3685 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)
3686 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)
3687 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)
3688 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)
3689 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
3690 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)
3691 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
3692 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.
3715 // CSQC range #300-#399
3716 NULL, // #300 void() clearscene (EXT_CSQC)
3717 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3718 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3719 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3720 NULL, // #304 void() renderscene (EXT_CSQC)
3721 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3722 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3723 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3724 NULL, // #308 void() R_EndPolygon
3726 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3727 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3731 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3732 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3733 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3734 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3735 NULL, // #319 void(string name) freepic (EXT_CSQC)
3736 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3737 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3738 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3739 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3740 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3741 NULL, // #325 void(void) drawresetcliparea
3746 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3747 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3748 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3749 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3750 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3751 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3752 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3753 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3754 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3755 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3756 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3757 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3758 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3759 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3760 NULL, // #344 vector() getmousepos (EXT_CSQC)
3761 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3762 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3763 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3764 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3765 NULL, // #349 float() isdemo (EXT_CSQC)
3766 VM_isserver, // #350 float() isserver (EXT_CSQC)
3767 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3768 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3769 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3770 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3776 NULL, // #360 float() readbyte (EXT_CSQC)
3777 NULL, // #361 float() readchar (EXT_CSQC)
3778 NULL, // #362 float() readshort (EXT_CSQC)
3779 NULL, // #363 float() readlong (EXT_CSQC)
3780 NULL, // #364 float() readcoord (EXT_CSQC)
3781 NULL, // #365 float() readangle (EXT_CSQC)
3782 NULL, // #366 string() readstring (EXT_CSQC)
3783 NULL, // #367 float() readfloat (EXT_CSQC)
3816 // LordHavoc's range #400-#499
3817 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3818 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3819 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3820 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3821 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3822 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3823 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3824 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3825 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)
3826 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3827 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3828 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3829 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3830 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3831 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3832 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3833 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3834 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3835 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3836 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3837 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3838 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3839 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3840 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3841 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3842 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3843 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3844 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3845 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3846 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3847 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3848 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3849 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3850 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3851 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3852 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3853 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3854 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3855 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3856 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3857 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3858 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3859 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3860 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3861 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3862 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3863 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3864 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3865 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3866 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3867 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3868 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3869 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3870 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3871 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3872 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3873 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3874 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3876 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3877 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3878 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3879 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3880 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3881 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3882 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3883 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3884 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3885 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3886 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3888 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3889 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3890 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3891 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3892 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3893 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3894 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3895 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3896 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3897 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3898 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3899 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3900 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3901 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3902 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3903 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3911 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3912 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3913 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3914 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3915 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3916 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3917 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3918 VM_SV_WritePicture, // #501
3920 VM_whichpack, // #503 string(string) whichpack = #503;
3927 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3928 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3929 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3930 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3931 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3932 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3933 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3934 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3935 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3936 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3946 VM_loadfromdata, // #529
3947 VM_loadfromfile, // #530
3948 VM_SV_setpause, // #531 void(float pause) setpause = #531;
4022 VM_callfunction, // #605
4023 VM_writetofile, // #606
4024 VM_isfunction, // #607
4030 VM_parseentitydata, // #613
4041 VM_SV_getextresponse, // #624 string getextresponse(void)
4044 VM_sprintf, // #627 string sprintf(string format, ...)
4045 VM_SV_traceboxbox, // #628
4049 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4051 void VM_SV_Cmd_Init(void)
4056 void VM_SV_Cmd_Reset(void)
4058 World_End(&sv.world);
4059 if(prog->funcoffsets.SV_Shutdown)
4061 func_t s = prog->funcoffsets.SV_Shutdown;
4062 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4063 PRVM_ExecuteProgram(s,"SV_Shutdown() required");