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 "
104 "DP_QC_STRINGBUFFERS "
105 "DP_QC_STRINGBUFFERS_CVARLIST "
106 "DP_QC_STRINGCOLORFUNCTIONS "
107 "DP_QC_STRING_CASE_FUNCTIONS "
109 "DP_QC_TOKENIZEBYSEPARATOR "
110 "DP_QC_TOKENIZE_CONSOLE "
113 "DP_QC_TRACE_MOVETYPE_HITMODEL "
114 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
115 "DP_QC_UNLIMITEDTEMPSTRINGS "
118 "DP_QC_VECTOANGLES_WITH_ROLL "
119 "DP_QC_VECTORVECTORS "
126 "DP_SKELETONOBJECTS "
127 "DP_SND_DIRECTIONLESSATTNNONE "
135 "DP_SV_BOUNCEFACTOR "
136 "DP_SV_CLIENTCOLORS "
139 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
140 "DP_SV_DRAWONLYTOCLIENT "
143 "DP_SV_ENTITYCONTENTSTRANSITION "
144 "DP_SV_MODELFLAGS_AS_EFFECTS "
145 "DP_SV_MOVETYPESTEP_LANDEVENT "
147 "DP_SV_NODRAWTOCLIENT "
148 "DP_SV_ONENTITYNOSPAWNFUNCTION "
149 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
151 "DP_SV_PING_PACKETLOSS "
152 "DP_SV_PLAYERPHYSICS "
153 "DP_SV_POINTPARTICLES "
155 "DP_SV_PRECACHEANYTIME "
159 "DP_SV_ROTATINGBMODEL "
163 "DP_SV_SPAWNFUNC_PREFIX "
164 "DP_SV_WRITEPICTURE "
165 "DP_SV_WRITEUNTERMINATEDSTRING "
169 "DP_TE_EXPLOSIONRGB "
171 "DP_TE_PARTICLECUBE "
172 "DP_TE_PARTICLERAIN "
173 "DP_TE_PARTICLESNOW "
175 "DP_TE_QUADEFFECTS1 "
178 "DP_TE_STANDARDEFFECTBUILTINS "
179 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
183 "FTE_CSQC_SKELETONOBJECTS "
186 "KRIMZON_SV_PARSECLIENTCOMMAND "
189 "NEXUIZ_PLAYERMODEL "
191 "PRYDON_CLIENTCURSOR "
192 "TENEBRAE_GFX_DLIGHTS "
195 //"EXT_CSQC " // not ready yet
202 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.
204 setorigin (entity, origin)
207 static void VM_SV_setorigin (void)
212 VM_SAFEPARMCOUNT(2, VM_setorigin);
214 e = PRVM_G_EDICT(OFS_PARM0);
215 if (e == prog->edicts)
217 VM_Warning("setorigin: can not modify world entity\n");
220 if (e->priv.server->free)
222 VM_Warning("setorigin: can not modify free entity\n");
225 org = PRVM_G_VECTOR(OFS_PARM1);
226 VectorCopy (org, e->fields.server->origin);
230 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
231 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
235 for (i=0 ; i<3 ; i++)
237 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
239 // set derived values
240 VectorCopy (min, e->fields.server->mins);
241 VectorCopy (max, e->fields.server->maxs);
242 VectorSubtract (max, min, e->fields.server->size);
251 the size box is rotated by the current angle
252 LordHavoc: no it isn't...
254 setsize (entity, minvector, maxvector)
257 static void VM_SV_setsize (void)
262 VM_SAFEPARMCOUNT(3, VM_setsize);
264 e = PRVM_G_EDICT(OFS_PARM0);
265 if (e == prog->edicts)
267 VM_Warning("setsize: can not modify world entity\n");
270 if (e->priv.server->free)
272 VM_Warning("setsize: can not modify free entity\n");
275 min = PRVM_G_VECTOR(OFS_PARM1);
276 max = PRVM_G_VECTOR(OFS_PARM2);
277 SetMinMaxSize (e, min, max, false);
285 setmodel(entity, model)
288 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
289 static void VM_SV_setmodel (void)
295 VM_SAFEPARMCOUNT(2, VM_setmodel);
297 e = PRVM_G_EDICT(OFS_PARM0);
298 if (e == prog->edicts)
300 VM_Warning("setmodel: can not modify world entity\n");
303 if (e->priv.server->free)
305 VM_Warning("setmodel: can not modify free entity\n");
308 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
309 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
310 e->fields.server->modelindex = i;
312 mod = SV_GetModelByIndex(i);
316 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
317 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
319 SetMinMaxSize (e, quakemins, quakemaxs, true);
322 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
329 single print to a specific client
331 sprint(clientent, value)
334 static void VM_SV_sprint (void)
338 char string[VM_STRINGTEMP_LENGTH];
340 VM_VarString(1, string, sizeof(string));
342 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
344 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
345 // LordHavoc: div0 requested that sprintto world operate like print
352 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
354 VM_Warning("tried to centerprint to a non-client\n");
358 client = svs.clients + entnum-1;
359 if (!client->netconnection)
362 MSG_WriteChar(&client->netconnection->message,svc_print);
363 MSG_WriteString(&client->netconnection->message, string);
371 single print to a specific client
373 centerprint(clientent, value)
376 static void VM_SV_centerprint (void)
380 char string[VM_STRINGTEMP_LENGTH];
382 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
384 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
386 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
388 VM_Warning("tried to centerprint to a non-client\n");
392 client = svs.clients + entnum-1;
393 if (!client->netconnection)
396 VM_VarString(1, string, sizeof(string));
397 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
398 MSG_WriteString(&client->netconnection->message, string);
405 particle(origin, color, count)
408 static void VM_SV_particle (void)
414 VM_SAFEPARMCOUNT(4, VM_SV_particle);
416 org = PRVM_G_VECTOR(OFS_PARM0);
417 dir = PRVM_G_VECTOR(OFS_PARM1);
418 color = PRVM_G_FLOAT(OFS_PARM2);
419 count = PRVM_G_FLOAT(OFS_PARM3);
420 SV_StartParticle (org, dir, (int)color, (int)count);
430 static void VM_SV_ambientsound (void)
434 float vol, attenuation;
437 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
439 pos = PRVM_G_VECTOR (OFS_PARM0);
440 samp = PRVM_G_STRING(OFS_PARM1);
441 vol = PRVM_G_FLOAT(OFS_PARM2);
442 attenuation = PRVM_G_FLOAT(OFS_PARM3);
444 // check to see if samp was properly precached
445 soundnum = SV_SoundIndex(samp, 1);
453 // add an svc_spawnambient command to the level signon packet
456 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
458 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
460 MSG_WriteVector(&sv.signon, pos, sv.protocol);
462 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
463 MSG_WriteShort (&sv.signon, soundnum);
465 MSG_WriteByte (&sv.signon, soundnum);
467 MSG_WriteByte (&sv.signon, (int)(vol*255));
468 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
476 Each entity can have eight independant sound sources, like voice,
479 Channel 0 is an auto-allocate channel, the others override anything
480 already running on that entity/channel pair.
482 An attenuation of 0 will play full volume everywhere in the level.
483 Larger attenuations will drop off.
487 static void VM_SV_sound (void)
491 prvm_edict_t *entity;
495 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
497 entity = PRVM_G_EDICT(OFS_PARM0);
498 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
499 sample = PRVM_G_STRING(OFS_PARM2);
500 volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
501 attenuation = PRVM_G_FLOAT(OFS_PARM4);
504 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
508 if (volume < 0 || volume > 255)
510 VM_Warning("SV_StartSound: volume must be in range 0-1\n");
514 if (attenuation < 0 || attenuation > 4)
516 VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
520 if (channel < 0 || channel > 7)
522 VM_Warning("SV_StartSound: channel must be in range 0-7\n");
526 SV_StartSound (entity, channel, sample, volume, attenuation);
533 Follows the same logic as VM_SV_sound, except instead of
534 an entity, an origin for the sound is provided, and channel
535 is omitted (since no entity is being tracked).
539 static void VM_SV_pointsound(void)
546 VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
548 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
549 sample = PRVM_G_STRING(OFS_PARM1);
550 volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
551 attenuation = PRVM_G_FLOAT(OFS_PARM3);
553 if (volume < 0 || volume > 255)
555 VM_Warning("SV_StartPointSound: volume must be in range 0-1\n");
559 if (attenuation < 0 || attenuation > 4)
561 VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
565 SV_StartPointSound (org, sample, volume, attenuation);
572 Used for use tracing and shot targeting
573 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
574 if the tryents flag is set.
576 traceline (vector1, vector2, movetype, ignore)
579 static void VM_SV_traceline (void)
586 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
588 prog->xfunction->builtinsprofile += 30;
590 v1 = PRVM_G_VECTOR(OFS_PARM0);
591 v2 = PRVM_G_VECTOR(OFS_PARM1);
592 move = (int)PRVM_G_FLOAT(OFS_PARM2);
593 ent = PRVM_G_EDICT(OFS_PARM3);
595 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]))
596 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));
598 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
600 VM_SetTraceGlobals(&trace);
608 Used for use tracing and shot targeting
609 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
610 if the tryents flag is set.
612 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
615 // LordHavoc: added this for my own use, VERY useful, similar to traceline
616 static void VM_SV_tracebox (void)
618 float *v1, *v2, *m1, *m2;
623 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
625 prog->xfunction->builtinsprofile += 30;
627 v1 = PRVM_G_VECTOR(OFS_PARM0);
628 m1 = PRVM_G_VECTOR(OFS_PARM1);
629 m2 = PRVM_G_VECTOR(OFS_PARM2);
630 v2 = PRVM_G_VECTOR(OFS_PARM3);
631 move = (int)PRVM_G_FLOAT(OFS_PARM4);
632 ent = PRVM_G_EDICT(OFS_PARM5);
634 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]))
635 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));
637 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
639 VM_SetTraceGlobals(&trace);
642 static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
647 vec3_t original_origin;
648 vec3_t original_velocity;
649 vec3_t original_angles;
650 vec3_t original_avelocity;
654 VectorCopy(tossent->fields.server->origin , original_origin );
655 VectorCopy(tossent->fields.server->velocity , original_velocity );
656 VectorCopy(tossent->fields.server->angles , original_angles );
657 VectorCopy(tossent->fields.server->avelocity, original_avelocity);
659 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
660 if (val != NULL && val->_float != 0)
661 gravity = val->_float;
664 gravity *= sv_gravity.value * 0.025;
666 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
668 SV_CheckVelocity (tossent);
669 tossent->fields.server->velocity[2] -= gravity;
670 VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
671 VectorScale (tossent->fields.server->velocity, 0.05, move);
672 VectorAdd (tossent->fields.server->origin, move, end);
673 trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
674 VectorCopy (trace.endpos, tossent->fields.server->origin);
675 tossent->fields.server->velocity[2] -= gravity;
677 if (trace.fraction < 1)
681 VectorCopy(original_origin , tossent->fields.server->origin );
682 VectorCopy(original_velocity , tossent->fields.server->velocity );
683 VectorCopy(original_angles , tossent->fields.server->angles );
684 VectorCopy(original_avelocity, tossent->fields.server->avelocity);
689 static void VM_SV_tracetoss (void)
693 prvm_edict_t *ignore;
695 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
697 prog->xfunction->builtinsprofile += 600;
699 ent = PRVM_G_EDICT(OFS_PARM0);
700 if (ent == prog->edicts)
702 VM_Warning("tracetoss: can not use world entity\n");
705 ignore = PRVM_G_EDICT(OFS_PARM1);
707 trace = SV_Trace_Toss (ent, ignore);
709 VM_SetTraceGlobals(&trace);
712 //============================================================================
714 static int checkpvsbytes;
715 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
717 static int VM_SV_newcheckclient (int check)
723 // cycle to the next one
725 check = bound(1, check, svs.maxclients);
726 if (check == svs.maxclients)
734 prog->xfunction->builtinsprofile++;
736 if (i == svs.maxclients+1)
738 // look up the client's edict
739 ent = PRVM_EDICT_NUM(i);
740 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
741 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
743 // found a valid client (possibly the same one again)
747 // get the PVS for the entity
748 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
750 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
751 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
760 Returns a client (or object that has a client enemy) that would be a
763 If there is more than one valid option, they are cycled each frame
765 If (self.origin + self.viewofs) is not in the PVS of the current target,
766 it is not returned at all.
771 int c_invis, c_notvis;
772 static void VM_SV_checkclient (void)
774 prvm_edict_t *ent, *self;
777 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
779 // find a new check if on a new frame
780 if (sv.time - sv.lastchecktime >= 0.1)
782 sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
783 sv.lastchecktime = sv.time;
786 // return check if it might be visible
787 ent = PRVM_EDICT_NUM(sv.lastcheck);
788 if (ent->priv.server->free || ent->fields.server->health <= 0)
790 VM_RETURN_EDICT(prog->edicts);
794 // if current entity can't possibly see the check entity, return 0
795 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
796 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
797 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
800 VM_RETURN_EDICT(prog->edicts);
804 // might be able to see it
806 VM_RETURN_EDICT(ent);
809 //============================================================================
815 Checks if an entity is in a point's PVS.
816 Should be fast but can be inexact.
818 float checkpvs(vector viewpos, entity viewee) = #240;
821 static void VM_SV_checkpvs (void)
824 prvm_edict_t *viewee;
829 unsigned char fatpvs[MAX_MAP_LEAFS/8];
832 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
833 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
834 viewee = PRVM_G_EDICT(OFS_PARM1);
836 if(viewee->priv.server->free)
838 VM_Warning("checkpvs: can not check free entity\n");
839 PRVM_G_FLOAT(OFS_RETURN) = 4;
844 if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
846 // no PVS support on this worldmodel... darn
847 PRVM_G_FLOAT(OFS_RETURN) = 3;
850 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
853 // viewpos isn't in any PVS... darn
854 PRVM_G_FLOAT(OFS_RETURN) = 2;
857 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
859 // using fat PVS like FTEQW does (slow)
860 if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
862 // no PVS support on this worldmodel... darn
863 PRVM_G_FLOAT(OFS_RETURN) = 3;
866 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
869 // viewpos isn't in any PVS... darn
870 PRVM_G_FLOAT(OFS_RETURN) = 2;
873 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
882 Sends text over to the client's execution buffer
884 stuffcmd (clientent, value, ...)
887 static void VM_SV_stuffcmd (void)
891 char string[VM_STRINGTEMP_LENGTH];
893 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
895 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
896 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
898 VM_Warning("Can't stuffcmd to a non-client\n");
902 VM_VarString(1, string, sizeof(string));
905 host_client = svs.clients + entnum-1;
906 Host_ClientCommands ("%s", string);
914 Returns a chain of entities that have origins within a spherical area
916 findradius (origin, radius)
919 static void VM_SV_findradius (void)
921 prvm_edict_t *ent, *chain;
922 vec_t radius, radius2;
923 vec3_t org, eorg, mins, maxs;
926 static prvm_edict_t *touchedicts[MAX_EDICTS];
929 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
932 chainfield = PRVM_G_INT(OFS_PARM2);
934 chainfield = prog->fieldoffsets.chain;
936 PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
938 chain = (prvm_edict_t *)prog->edicts;
940 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
941 radius = PRVM_G_FLOAT(OFS_PARM1);
942 radius2 = radius * radius;
944 mins[0] = org[0] - (radius + 1);
945 mins[1] = org[1] - (radius + 1);
946 mins[2] = org[2] - (radius + 1);
947 maxs[0] = org[0] + (radius + 1);
948 maxs[1] = org[1] + (radius + 1);
949 maxs[2] = org[2] + (radius + 1);
950 numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
951 if (numtouchedicts > MAX_EDICTS)
953 // this never happens
954 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
955 numtouchedicts = MAX_EDICTS;
957 for (i = 0;i < numtouchedicts;i++)
959 ent = touchedicts[i];
960 prog->xfunction->builtinsprofile++;
961 // Quake did not return non-solid entities but darkplaces does
962 // (note: this is the reason you can't blow up fallen zombies)
963 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
965 // LordHavoc: compare against bounding box rather than center so it
966 // doesn't miss large objects, and use DotProduct instead of Length
967 // for a major speedup
968 VectorSubtract(org, ent->fields.server->origin, eorg);
969 if (sv_gameplayfix_findradiusdistancetobox.integer)
971 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
972 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
973 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
976 VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
977 if (DotProduct(eorg, eorg) < radius2)
979 PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
984 VM_RETURN_EDICT(chain);
987 static void VM_SV_precache_sound (void)
989 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
990 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
993 static void VM_SV_precache_model (void)
995 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
996 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
997 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1004 float(float yaw, float dist[, settrace]) walkmove
1007 static void VM_SV_walkmove (void)
1016 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1018 // assume failure if it returns early
1019 PRVM_G_FLOAT(OFS_RETURN) = 0;
1021 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1022 if (ent == prog->edicts)
1024 VM_Warning("walkmove: can not modify world entity\n");
1027 if (ent->priv.server->free)
1029 VM_Warning("walkmove: can not modify free entity\n");
1032 yaw = PRVM_G_FLOAT(OFS_PARM0);
1033 dist = PRVM_G_FLOAT(OFS_PARM1);
1034 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1036 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1039 yaw = yaw*M_PI*2 / 360;
1041 move[0] = cos(yaw)*dist;
1042 move[1] = sin(yaw)*dist;
1045 // save program state, because SV_movestep may call other progs
1046 oldf = prog->xfunction;
1047 oldself = prog->globals.server->self;
1049 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1052 // restore program state
1053 prog->xfunction = oldf;
1054 prog->globals.server->self = oldself;
1064 static void VM_SV_droptofloor (void)
1070 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1072 // assume failure if it returns early
1073 PRVM_G_FLOAT(OFS_RETURN) = 0;
1075 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1076 if (ent == prog->edicts)
1078 VM_Warning("droptofloor: can not modify world entity\n");
1081 if (ent->priv.server->free)
1083 VM_Warning("droptofloor: can not modify free entity\n");
1087 VectorCopy (ent->fields.server->origin, end);
1090 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1091 SV_UnstickEntity(ent);
1093 trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1094 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1097 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]);
1098 VectorAdd(ent->fields.server->origin, offset, org);
1099 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1100 VectorSubtract(trace.endpos, offset, trace.endpos);
1101 if (trace.startsolid)
1103 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]);
1104 SV_UnstickEntity(ent);
1106 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1107 ent->fields.server->groundentity = 0;
1108 PRVM_G_FLOAT(OFS_RETURN) = 1;
1110 else if (trace.fraction < 1)
1112 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]);
1113 VectorCopy (trace.endpos, ent->fields.server->origin);
1114 SV_UnstickEntity(ent);
1116 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1117 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1118 PRVM_G_FLOAT(OFS_RETURN) = 1;
1119 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1120 ent->priv.server->suspendedinairflag = true;
1125 if (trace.fraction != 1)
1127 if (trace.fraction < 1)
1128 VectorCopy (trace.endpos, ent->fields.server->origin);
1130 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1131 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1132 PRVM_G_FLOAT(OFS_RETURN) = 1;
1133 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1134 ent->priv.server->suspendedinairflag = true;
1143 void(float style, string value) lightstyle
1146 static void VM_SV_lightstyle (void)
1153 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1155 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1156 val = PRVM_G_STRING(OFS_PARM1);
1158 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1159 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
1162 // change the string in sv
1163 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1165 // send message to all clients on this server
1166 if (sv.state != ss_active)
1169 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1171 if (client->active && client->netconnection)
1173 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1174 MSG_WriteChar (&client->netconnection->message,style);
1175 MSG_WriteString (&client->netconnection->message, val);
1185 static void VM_SV_checkbottom (void)
1187 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1188 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1196 static void VM_SV_pointcontents (void)
1198 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1199 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1206 Pick a vector for the player to shoot along
1207 vector aim(entity, missilespeed)
1210 static void VM_SV_aim (void)
1212 prvm_edict_t *ent, *check, *bestent;
1213 vec3_t start, dir, end, bestdir;
1216 float dist, bestdist;
1219 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1221 // assume failure if it returns early
1222 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1223 // if sv_aim is so high it can't possibly accept anything, skip out early
1224 if (sv_aim.value >= 1)
1227 ent = PRVM_G_EDICT(OFS_PARM0);
1228 if (ent == prog->edicts)
1230 VM_Warning("aim: can not use world entity\n");
1233 if (ent->priv.server->free)
1235 VM_Warning("aim: can not use free entity\n");
1238 speed = PRVM_G_FLOAT(OFS_PARM1);
1240 VectorCopy (ent->fields.server->origin, start);
1243 // try sending a trace straight
1244 VectorCopy (prog->globals.server->v_forward, dir);
1245 VectorMA (start, 2048, dir, end);
1246 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1247 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1248 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1250 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1255 // try all possible entities
1256 VectorCopy (dir, bestdir);
1257 bestdist = sv_aim.value;
1260 check = PRVM_NEXT_EDICT(prog->edicts);
1261 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1263 prog->xfunction->builtinsprofile++;
1264 if (check->fields.server->takedamage != DAMAGE_AIM)
1268 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1269 continue; // don't aim at teammate
1270 for (j=0 ; j<3 ; j++)
1271 end[j] = check->fields.server->origin[j]
1272 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1273 VectorSubtract (end, start, dir);
1274 VectorNormalize (dir);
1275 dist = DotProduct (dir, prog->globals.server->v_forward);
1276 if (dist < bestdist)
1277 continue; // to far to turn
1278 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1279 if (tr.ent == check)
1280 { // can shoot at this one
1288 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1289 dist = DotProduct (dir, prog->globals.server->v_forward);
1290 VectorScale (prog->globals.server->v_forward, dist, end);
1292 VectorNormalize (end);
1293 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1297 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1302 ===============================================================================
1306 ===============================================================================
1309 #define MSG_BROADCAST 0 // unreliable to all
1310 #define MSG_ONE 1 // reliable to one (msg_entity)
1311 #define MSG_ALL 2 // reliable to all
1312 #define MSG_INIT 3 // write to the init string
1313 #define MSG_ENTITY 5
1315 sizebuf_t *WriteDest (void)
1321 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1325 return &sv.datagram;
1328 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1329 entnum = PRVM_NUM_FOR_EDICT(ent);
1330 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1332 VM_Warning ("WriteDest: tried to write to non-client\n");
1333 return &sv.reliable_datagram;
1336 return &svs.clients[entnum-1].netconnection->message;
1339 VM_Warning ("WriteDest: bad destination\n");
1341 return &sv.reliable_datagram;
1347 return sv.writeentitiestoclient_msg;
1353 static void VM_SV_WriteByte (void)
1355 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1356 MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1359 static void VM_SV_WriteChar (void)
1361 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1362 MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1365 static void VM_SV_WriteShort (void)
1367 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1368 MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1371 static void VM_SV_WriteLong (void)
1373 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1374 MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1377 static void VM_SV_WriteAngle (void)
1379 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1380 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1383 static void VM_SV_WriteCoord (void)
1385 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1386 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1389 static void VM_SV_WriteString (void)
1391 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1392 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1395 static void VM_SV_WriteUnterminatedString (void)
1397 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1398 MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1401 static void VM_SV_WriteEntity (void)
1403 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1404 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1407 static void VM_SV_WriteByteINT (void)
1409 VM_SAFEPARMCOUNT(2, VM_SV_WriteByteINT);
1410 MSG_WriteByte (WriteDest(), PRVM_G_INT(OFS_PARM1));
1413 static void VM_SV_WriteCharINT (void)
1415 VM_SAFEPARMCOUNT(2, VM_SV_WriteCharINT);
1416 MSG_WriteChar (WriteDest(), PRVM_G_INT(OFS_PARM1));
1419 static void VM_SV_WriteShortINT (void)
1421 VM_SAFEPARMCOUNT(2, VM_SV_WriteShortINT);
1422 MSG_WriteShort (WriteDest(), PRVM_G_INT(OFS_PARM1));
1425 static void VM_SV_WriteLongINT (void)
1427 VM_SAFEPARMCOUNT(2, VM_SV_WriteLongINT);
1428 MSG_WriteLong (WriteDest(), PRVM_G_INT(OFS_PARM1));
1432 // writes a picture as at most size bytes of data
1434 // IMGNAME \0 SIZE(short) IMGDATA
1435 // if failed to read/compress:
1437 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1438 static void VM_SV_WritePicture (void)
1440 const char *imgname;
1444 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1446 imgname = PRVM_G_STRING(OFS_PARM1);
1447 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1451 MSG_WriteString(WriteDest(), imgname);
1452 if(Image_Compress(imgname, size, &buf, &size))
1455 MSG_WriteShort(WriteDest(), size);
1456 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1461 MSG_WriteShort(WriteDest(), 0);
1465 //////////////////////////////////////////////////////////
1467 static void VM_SV_makestatic (void)
1472 // allow 0 parameters due to an id1 qc bug in which this function is used
1473 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1474 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1476 if (prog->argc >= 1)
1477 ent = PRVM_G_EDICT(OFS_PARM0);
1479 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1480 if (ent == prog->edicts)
1482 VM_Warning("makestatic: can not modify world entity\n");
1485 if (ent->priv.server->free)
1487 VM_Warning("makestatic: can not modify free entity\n");
1492 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1497 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1498 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1499 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1501 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1503 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1504 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1505 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1509 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1510 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1511 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1514 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1515 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1516 for (i=0 ; i<3 ; i++)
1518 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1519 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1522 // throw the entity away now
1526 //=============================================================================
1533 static void VM_SV_setspawnparms (void)
1539 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1541 ent = PRVM_G_EDICT(OFS_PARM0);
1542 i = PRVM_NUM_FOR_EDICT(ent);
1543 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1545 Con_Print("tried to setspawnparms on a non-client\n");
1549 // copy spawn parms out of the client_t
1550 client = svs.clients + i-1;
1551 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1552 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1559 Returns a color vector indicating the lighting at the requested point.
1561 (Internal Operation note: actually measures the light beneath the point, just like
1562 the model lighting on the client)
1567 static void VM_SV_getlight (void)
1569 vec3_t ambientcolor, diffusecolor, diffusenormal;
1571 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1572 p = PRVM_G_VECTOR(OFS_PARM0);
1573 VectorClear(ambientcolor);
1574 VectorClear(diffusecolor);
1575 VectorClear(diffusenormal);
1576 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1577 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1578 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1583 unsigned char type; // 1/2/8 or other value if isn't used
1587 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1588 static int vm_customstats_last;
1590 void VM_CustomStats_Clear (void)
1594 Z_Free(vm_customstats);
1595 vm_customstats = NULL;
1596 vm_customstats_last = -1;
1600 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1608 for(i=0; i<vm_customstats_last+1 ;i++)
1610 if(!vm_customstats[i].type)
1612 switch(vm_customstats[i].type)
1614 //string as 16 bytes
1617 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1618 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1619 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1620 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1621 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1623 //float field sent as-is
1625 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1627 //integer value of float field
1629 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1637 // void(float index, float type, .void field) SV_AddStat = #232;
1638 // Set up an auto-sent player stat.
1639 // Client's get thier own fields sent to them. Index may not be less than 32.
1640 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1641 // 1: string (4 stats carrying a total of 16 charactures)
1642 // 2: float (one stat, float converted to an integer for transportation)
1643 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1644 static void VM_SV_AddStat (void)
1649 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1653 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1656 VM_Warning("PF_SV_AddStat: not enough memory\n");
1660 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1661 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1662 off = PRVM_G_INT (OFS_PARM2);
1667 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1670 if(i >= (MAX_CL_STATS-32))
1672 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1675 if(i > (MAX_CL_STATS-32-4) && type == 1)
1677 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1680 vm_customstats[i].type = type;
1681 vm_customstats[i].fieldoffset = off;
1682 if(vm_customstats_last < i)
1683 vm_customstats_last = i;
1690 copies data from one entity to another
1692 copyentity(src, dst)
1695 static void VM_SV_copyentity (void)
1697 prvm_edict_t *in, *out;
1698 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1699 in = PRVM_G_EDICT(OFS_PARM0);
1700 if (in == prog->edicts)
1702 VM_Warning("copyentity: can not read world entity\n");
1705 if (in->priv.server->free)
1707 VM_Warning("copyentity: can not read free entity\n");
1710 out = PRVM_G_EDICT(OFS_PARM1);
1711 if (out == prog->edicts)
1713 VM_Warning("copyentity: can not modify world entity\n");
1716 if (out->priv.server->free)
1718 VM_Warning("copyentity: can not modify free entity\n");
1721 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1730 sets the color of a client and broadcasts the update to all connected clients
1732 setcolor(clientent, value)
1735 static void VM_SV_setcolor (void)
1741 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1742 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1743 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1745 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1747 Con_Print("tried to setcolor a non-client\n");
1751 client = svs.clients + entnum-1;
1754 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1756 client->edict->fields.server->team = (i & 15) + 1;
1759 if (client->old_colors != client->colors)
1761 client->old_colors = client->colors;
1762 // send notification to all clients
1763 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1764 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1765 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1773 effect(origin, modelname, startframe, framecount, framerate)
1776 static void VM_SV_effect (void)
1780 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1781 s = PRVM_G_STRING(OFS_PARM1);
1784 VM_Warning("effect: no model specified\n");
1788 i = SV_ModelIndex(s, 1);
1791 VM_Warning("effect: model not precached\n");
1795 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1797 VM_Warning("effect: framecount < 1\n");
1801 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1803 VM_Warning("effect: framerate < 1\n");
1807 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));
1810 static void VM_SV_te_blood (void)
1812 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1813 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1815 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1816 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1818 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1819 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1820 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1822 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1823 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1824 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1826 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1827 SV_FlushBroadcastMessages();
1830 static void VM_SV_te_bloodshower (void)
1832 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1833 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1835 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1836 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1838 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1839 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1840 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1842 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1843 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1844 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1846 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1848 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1849 SV_FlushBroadcastMessages();
1852 static void VM_SV_te_explosionrgb (void)
1854 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1855 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1856 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1858 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1859 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1860 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1862 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1863 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1864 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1865 SV_FlushBroadcastMessages();
1868 static void VM_SV_te_particlecube (void)
1870 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1871 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1873 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1874 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1876 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1877 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1878 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1880 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1881 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1882 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1885 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1886 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1888 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1890 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1891 // gravity true/false
1892 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1894 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1895 SV_FlushBroadcastMessages();
1898 static void VM_SV_te_particlerain (void)
1900 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1901 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1903 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1904 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1906 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1908 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1912 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1914 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1915 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1916 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1918 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1920 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1921 SV_FlushBroadcastMessages();
1924 static void VM_SV_te_particlesnow (void)
1926 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1927 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1929 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1930 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1932 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1933 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1934 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1936 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1937 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1938 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1940 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1941 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1942 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1944 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1946 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1947 SV_FlushBroadcastMessages();
1950 static void VM_SV_te_spark (void)
1952 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1953 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1955 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1956 MSG_WriteByte(&sv.datagram, TE_SPARK);
1958 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1959 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1960 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1962 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1963 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1964 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1966 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1967 SV_FlushBroadcastMessages();
1970 static void VM_SV_te_gunshotquad (void)
1972 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1973 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1974 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1976 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1977 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1978 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1979 SV_FlushBroadcastMessages();
1982 static void VM_SV_te_spikequad (void)
1984 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
1985 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1986 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1988 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1989 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1990 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1991 SV_FlushBroadcastMessages();
1994 static void VM_SV_te_superspikequad (void)
1996 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
1997 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1998 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2000 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2002 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2003 SV_FlushBroadcastMessages();
2006 static void VM_SV_te_explosionquad (void)
2008 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2009 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2010 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2012 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2013 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2014 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2015 SV_FlushBroadcastMessages();
2018 static void VM_SV_te_smallflash (void)
2020 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2021 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2022 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2024 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2025 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2026 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2027 SV_FlushBroadcastMessages();
2030 static void VM_SV_te_customflash (void)
2032 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2033 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2035 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2036 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2038 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2039 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2040 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2042 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2044 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2046 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2047 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2048 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2049 SV_FlushBroadcastMessages();
2052 static void VM_SV_te_gunshot (void)
2054 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2055 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2056 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2058 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2059 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2060 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2061 SV_FlushBroadcastMessages();
2064 static void VM_SV_te_spike (void)
2066 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2067 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2068 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2070 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2071 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2072 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2073 SV_FlushBroadcastMessages();
2076 static void VM_SV_te_superspike (void)
2078 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2079 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2080 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2082 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2083 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2084 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2085 SV_FlushBroadcastMessages();
2088 static void VM_SV_te_explosion (void)
2090 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2091 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2092 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2094 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2095 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2096 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2097 SV_FlushBroadcastMessages();
2100 static void VM_SV_te_tarexplosion (void)
2102 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2103 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2104 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2106 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2107 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2108 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2109 SV_FlushBroadcastMessages();
2112 static void VM_SV_te_wizspike (void)
2114 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2115 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2116 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2118 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2119 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2120 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2121 SV_FlushBroadcastMessages();
2124 static void VM_SV_te_knightspike (void)
2126 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2127 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2128 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2130 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2131 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2132 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2133 SV_FlushBroadcastMessages();
2136 static void VM_SV_te_lavasplash (void)
2138 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2139 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2140 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2142 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2143 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2144 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2145 SV_FlushBroadcastMessages();
2148 static void VM_SV_te_teleport (void)
2150 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2151 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2152 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2154 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2155 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2156 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2157 SV_FlushBroadcastMessages();
2160 static void VM_SV_te_explosion2 (void)
2162 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2163 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2164 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2166 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2167 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2168 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2170 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2171 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2172 SV_FlushBroadcastMessages();
2175 static void VM_SV_te_lightning1 (void)
2177 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2178 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2179 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2181 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2185 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2187 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2188 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2189 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2190 SV_FlushBroadcastMessages();
2193 static void VM_SV_te_lightning2 (void)
2195 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2196 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2197 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2199 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2201 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2202 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2203 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2205 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2206 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2207 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2208 SV_FlushBroadcastMessages();
2211 static void VM_SV_te_lightning3 (void)
2213 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2214 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2215 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2217 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2221 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2223 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2224 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2225 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2226 SV_FlushBroadcastMessages();
2229 static void VM_SV_te_beam (void)
2231 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2232 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2233 MSG_WriteByte(&sv.datagram, TE_BEAM);
2235 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2237 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2238 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2239 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2244 SV_FlushBroadcastMessages();
2247 static void VM_SV_te_plasmaburn (void)
2249 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2250 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2251 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2252 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2253 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2254 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2255 SV_FlushBroadcastMessages();
2258 static void VM_SV_te_flamejet (void)
2260 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2261 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2262 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2264 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2265 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2266 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2268 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2272 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2273 SV_FlushBroadcastMessages();
2276 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2279 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2281 bestdist = 1000000000;
2283 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2285 // clip original point to each triangle of the surface and find the
2286 // triangle that is closest
2287 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2288 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2289 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2290 TriangleNormal(v[0], v[1], v[2], facenormal);
2291 VectorNormalize(facenormal);
2292 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2293 VectorMA(p, offsetdist, facenormal, temp);
2294 for (j = 0, k = 2;j < 3;k = j, j++)
2296 VectorSubtract(v[k], v[j], edgenormal);
2297 CrossProduct(edgenormal, facenormal, sidenormal);
2298 VectorNormalize(sidenormal);
2299 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2301 VectorMA(temp, offsetdist, sidenormal, temp);
2303 dist = VectorDistance2(temp, p);
2304 if (bestdist > dist)
2307 VectorCopy(temp, out);
2312 #define getmodel SV_GetModelFromEdict
2314 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2316 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2318 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2322 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2323 static void VM_SV_getsurfacenumpoints(void)
2326 msurface_t *surface;
2327 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2328 // return 0 if no such surface
2329 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2331 PRVM_G_FLOAT(OFS_RETURN) = 0;
2335 // note: this (incorrectly) assumes it is a simple polygon
2336 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2338 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2339 static void VM_SV_getsurfacepoint(void)
2343 msurface_t *surface;
2345 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2346 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2347 ed = PRVM_G_EDICT(OFS_PARM0);
2348 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2350 // note: this (incorrectly) assumes it is a simple polygon
2351 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2352 if (pointnum < 0 || pointnum >= surface->num_vertices)
2354 // FIXME: implement rotation/scaling
2355 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2357 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2358 // float SPA_POSITION = 0;
2359 // float SPA_S_AXIS = 1;
2360 // float SPA_T_AXIS = 2;
2361 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2362 // float SPA_TEXCOORDS0 = 4;
2363 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2364 // float SPA_LIGHTMAP0_COLOR = 6;
2365 static void VM_SV_getsurfacepointattribute(void)
2369 msurface_t *surface;
2373 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2374 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2375 ed = PRVM_G_EDICT(OFS_PARM0);
2376 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2378 // note: this (incorrectly) assumes it is a simple polygon
2379 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2380 if (pointnum < 0 || pointnum >= surface->num_vertices)
2382 // FIXME: implement rotation/scaling
2383 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2385 switch( attributetype ) {
2386 // float SPA_POSITION = 0;
2388 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2390 // float SPA_S_AXIS = 1;
2392 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2394 // float SPA_T_AXIS = 2;
2396 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2398 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2400 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2402 // float SPA_TEXCOORDS0 = 4;
2404 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2405 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2406 ret[0] = texcoord[0];
2407 ret[1] = texcoord[1];
2411 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2413 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2414 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2415 ret[0] = texcoord[0];
2416 ret[1] = texcoord[1];
2420 // float SPA_LIGHTMAP0_COLOR = 6;
2422 // ignore alpha for now..
2423 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2426 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2430 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2431 static void VM_SV_getsurfacenormal(void)
2434 msurface_t *surface;
2436 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2437 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2438 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2440 // FIXME: implement rotation/scaling
2441 // note: this (incorrectly) assumes it is a simple polygon
2442 // note: this only returns the first triangle, so it doesn't work very
2443 // well for curved surfaces or arbitrary meshes
2444 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);
2445 VectorNormalize(normal);
2446 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2448 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2449 static void VM_SV_getsurfacetexture(void)
2452 msurface_t *surface;
2453 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2454 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2455 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2457 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2459 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2460 static void VM_SV_getsurfacenearpoint(void)
2462 int surfacenum, best;
2464 vec_t dist, bestdist;
2467 msurface_t *surface;
2469 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2470 PRVM_G_FLOAT(OFS_RETURN) = -1;
2471 ed = PRVM_G_EDICT(OFS_PARM0);
2472 point = PRVM_G_VECTOR(OFS_PARM1);
2474 if (!ed || ed->priv.server->free)
2476 model = getmodel(ed);
2477 if (!model || !model->num_surfaces)
2480 // FIXME: implement rotation/scaling
2481 VectorSubtract(point, ed->fields.server->origin, p);
2483 bestdist = 1000000000;
2484 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2486 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2487 // first see if the nearest point on the surface's box is closer than the previous match
2488 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2489 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2490 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2491 dist = VectorLength2(clipped);
2492 if (dist < bestdist)
2494 // it is, check the nearest point on the actual geometry
2495 clippointtosurface(model, surface, p, clipped);
2496 VectorSubtract(clipped, p, clipped);
2497 dist += VectorLength2(clipped);
2498 if (dist < bestdist)
2500 // that's closer too, store it as the best match
2506 PRVM_G_FLOAT(OFS_RETURN) = best;
2508 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2509 static void VM_SV_getsurfaceclippedpoint(void)
2513 msurface_t *surface;
2515 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2516 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2517 ed = PRVM_G_EDICT(OFS_PARM0);
2518 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2520 // FIXME: implement rotation/scaling
2521 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2522 clippointtosurface(model, surface, p, out);
2523 // FIXME: implement rotation/scaling
2524 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2527 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2528 //this function originally written by KrimZon, made shorter by LordHavoc
2529 static void VM_SV_clientcommand (void)
2531 client_t *temp_client;
2533 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2535 //find client for this entity
2536 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2537 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2539 Con_Print("PF_clientcommand: entity is not a client\n");
2543 temp_client = host_client;
2544 host_client = svs.clients + i;
2545 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2546 host_client = temp_client;
2549 //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)
2550 static void VM_SV_setattachment (void)
2552 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2553 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2554 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2557 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2559 if (e == prog->edicts)
2561 VM_Warning("setattachment: can not modify world entity\n");
2564 if (e->priv.server->free)
2566 VM_Warning("setattachment: can not modify free entity\n");
2570 if (tagentity == NULL)
2571 tagentity = prog->edicts;
2573 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2575 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2577 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2580 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2582 model = SV_GetModelFromEdict(tagentity);
2585 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2587 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);
2590 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));
2594 /////////////////////////////////////////
2595 // DP_MD3_TAGINFO extension coded by VorteX
2597 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2601 i = (int)e->fields.server->modelindex;
2602 if (i < 1 || i >= MAX_MODELS)
2605 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2608 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2615 Matrix4x4_CreateIdentity(tag_localmatrix);
2617 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2619 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2630 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2634 float pitchsign = 1;
2637 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2638 if (val && val->_float != 0)
2639 scale = val->_float;
2642 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);
2645 pitchsign = SV_GetPitchSign(ent);
2646 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);
2650 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2653 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->num_bones)
2655 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2656 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2657 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2658 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2660 *out = identitymatrix;
2664 // Warnings/errors code:
2665 // 0 - normal (everything all-right)
2668 // 3 - null or non-precached model
2669 // 4 - no tags with requested index
2670 // 5 - runaway loop at attachment chain
2671 extern cvar_t cl_bob;
2672 extern cvar_t cl_bobcycle;
2673 extern cvar_t cl_bobup;
2674 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2678 int modelindex, attachloop;
2679 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2682 *out = identitymatrix; // warnings and errors return identical matrix
2684 if (ent == prog->edicts)
2686 if (ent->priv.server->free)
2689 modelindex = (int)ent->fields.server->modelindex;
2690 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2693 model = SV_GetModelByIndex(modelindex);
2695 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2696 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2697 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2699 tagmatrix = identitymatrix;
2700 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2704 if (attachloop >= 256) // prevent runaway looping
2706 // apply transformation by child's tagindex on parent entity and then
2707 // by parent entity itself
2708 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2709 if (ret && attachloop == 0)
2711 SV_GetEntityMatrix(ent, &entitymatrix, false);
2712 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2713 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2714 // next iteration we process the parent entity
2715 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2717 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2718 ent = PRVM_EDICT_NUM(val->edict);
2725 // RENDER_VIEWMODEL magic
2726 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2728 Matrix4x4_Copy(&tagmatrix, out);
2729 ent = PRVM_EDICT_NUM(val->edict);
2731 SV_GetEntityMatrix(ent, &entitymatrix, true);
2732 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2735 // Cl_bob, ported from rendering code
2736 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2739 // LordHavoc: this code is *weird*, but not replacable (I think it
2740 // should be done in QC on the server, but oh well, quake is quake)
2741 // LordHavoc: figured out bobup: the time at which the sin is at 180
2742 // degrees (which allows lengthening or squishing the peak or valley)
2743 cycle = sv.time/cl_bobcycle.value;
2744 cycle -= (int)cycle;
2745 if (cycle < cl_bobup.value)
2746 cycle = sin(M_PI * cycle / cl_bobup.value);
2748 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2749 // bob is proportional to velocity in the xy plane
2750 // (don't count Z, or jumping messes it up)
2751 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;
2752 bob = bob*0.3 + bob*0.7*cycle;
2753 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2760 //float(entity ent, string tagname) gettagindex;
2762 static void VM_SV_gettagindex (void)
2765 const char *tag_name;
2768 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2770 ent = PRVM_G_EDICT(OFS_PARM0);
2771 tag_name = PRVM_G_STRING(OFS_PARM1);
2773 if (ent == prog->edicts)
2775 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2778 if (ent->priv.server->free)
2780 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2785 if (!SV_GetModelFromEdict(ent))
2786 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2789 tag_index = SV_GetTagIndex(ent, tag_name);
2791 if(developer.integer >= 100)
2792 Con_Printf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2794 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2797 //vector(entity ent, float tagindex) gettaginfo;
2798 static void VM_SV_gettaginfo (void)
2802 matrix4x4_t tag_matrix;
2803 matrix4x4_t tag_localmatrix;
2805 const char *tagname;
2808 vec3_t fo, le, up, trans;
2809 const dp_model_t *model;
2811 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2813 e = PRVM_G_EDICT(OFS_PARM0);
2814 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2816 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2817 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2818 VectorScale(le, -1, prog->globals.server->v_right);
2819 model = SV_GetModelFromEdict(e);
2820 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2821 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2822 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2823 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2824 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2826 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2827 val->_float = parentindex;
2828 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2829 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2830 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2831 VectorCopy(trans, val->vector);
2832 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2833 VectorCopy(fo, val->vector);
2834 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2835 VectorScale(le, -1, val->vector);
2836 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2837 VectorCopy(up, val->vector);
2842 VM_Warning("gettagindex: can't affect world entity\n");
2845 VM_Warning("gettagindex: can't affect free entity\n");
2848 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2851 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2854 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2859 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2860 static void VM_SV_dropclient (void)
2863 client_t *oldhostclient;
2864 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2865 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2866 if (clientnum < 0 || clientnum >= svs.maxclients)
2868 VM_Warning("dropclient: not a client\n");
2871 if (!svs.clients[clientnum].active)
2873 VM_Warning("dropclient: that client slot is not connected\n");
2876 oldhostclient = host_client;
2877 host_client = svs.clients + clientnum;
2878 SV_DropClient(false);
2879 host_client = oldhostclient;
2882 //entity() spawnclient (DP_SV_BOTCLIENT)
2883 static void VM_SV_spawnclient (void)
2887 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2888 prog->xfunction->builtinsprofile += 2;
2890 for (i = 0;i < svs.maxclients;i++)
2892 if (!svs.clients[i].active)
2894 prog->xfunction->builtinsprofile += 100;
2895 SV_ConnectClient (i, NULL);
2896 // this has to be set or else ClientDisconnect won't be called
2897 // we assume the qc will call ClientConnect...
2898 svs.clients[i].clientconnectcalled = true;
2899 ed = PRVM_EDICT_NUM(i + 1);
2903 VM_RETURN_EDICT(ed);
2906 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2907 static void VM_SV_clienttype (void)
2910 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2911 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2912 if (clientnum < 0 || clientnum >= svs.maxclients)
2913 PRVM_G_FLOAT(OFS_RETURN) = 3;
2914 else if (!svs.clients[clientnum].active)
2915 PRVM_G_FLOAT(OFS_RETURN) = 0;
2916 else if (svs.clients[clientnum].netconnection)
2917 PRVM_G_FLOAT(OFS_RETURN) = 1;
2919 PRVM_G_FLOAT(OFS_RETURN) = 2;
2926 string(string key) serverkey
2929 void VM_SV_serverkey(void)
2931 char string[VM_STRINGTEMP_LENGTH];
2932 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2933 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2934 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2937 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2938 static void VM_SV_setmodelindex (void)
2943 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2945 e = PRVM_G_EDICT(OFS_PARM0);
2946 if (e == prog->edicts)
2948 VM_Warning("setmodelindex: can not modify world entity\n");
2951 if (e->priv.server->free)
2953 VM_Warning("setmodelindex: can not modify free entity\n");
2956 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2957 if (i <= 0 || i >= MAX_MODELS)
2959 VM_Warning("setmodelindex: invalid modelindex\n");
2962 if (!sv.model_precache[i][0])
2964 VM_Warning("setmodelindex: model not precached\n");
2968 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2969 e->fields.server->modelindex = i;
2971 mod = SV_GetModelByIndex(i);
2975 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2976 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2978 SetMinMaxSize (e, quakemins, quakemaxs, true);
2981 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
2984 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2985 static void VM_SV_modelnameforindex (void)
2988 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2990 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2992 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2993 if (i <= 0 || i >= MAX_MODELS)
2995 VM_Warning("modelnameforindex: invalid modelindex\n");
2998 if (!sv.model_precache[i][0])
3000 VM_Warning("modelnameforindex: model not precached\n");
3004 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
3007 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
3008 static void VM_SV_particleeffectnum (void)
3011 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
3012 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
3015 PRVM_G_FLOAT(OFS_RETURN) = i;
3018 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3019 static void VM_SV_trailparticles (void)
3021 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
3023 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3026 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3027 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3028 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3029 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3030 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3031 SV_FlushBroadcastMessages();
3034 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3035 static void VM_SV_pointparticles (void)
3037 int effectnum, count;
3039 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3041 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3044 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3045 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3046 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3047 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3048 if (count == 1 && !VectorLength2(vel))
3051 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3052 MSG_WriteShort(&sv.datagram, effectnum);
3053 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3057 // 1+2+12+12+2=29 bytes
3058 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3059 MSG_WriteShort(&sv.datagram, effectnum);
3060 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3061 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3062 MSG_WriteShort(&sv.datagram, count);
3065 SV_FlushBroadcastMessages();
3068 //PF_setpause, // void(float pause) setpause = #531;
3069 static void VM_SV_setpause(void) {
3071 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3072 if (pauseValue != 0) { //pause the game
3074 sv.pausedstart = Sys_DoubleTime();
3075 } else { //disable pause, in case it was enabled
3076 if (sv.paused != 0) {
3081 // send notification to all clients
3082 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3083 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3086 // #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.
3087 static void VM_SV_skel_create(void)
3089 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3090 dp_model_t *model = SV_GetModelByIndex(modelindex);
3091 skeleton_t *skeleton;
3093 PRVM_G_FLOAT(OFS_RETURN) = 0;
3094 if (!model || !model->num_bones)
3096 for (i = 0;i < MAX_EDICTS;i++)
3097 if (!prog->skeletons[i])
3099 if (i == MAX_EDICTS)
3101 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3102 skeleton->model = model;
3103 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3104 // initialize to identity matrices
3105 for (i = 0;i < skeleton->model->num_bones;i++)
3106 skeleton->relativetransforms[i] = identitymatrix;
3107 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3110 // #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
3111 static void VM_SV_skel_build(void)
3113 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3114 skeleton_t *skeleton;
3115 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3116 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3117 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3118 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3119 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3120 dp_model_t *model = SV_GetModelByIndex(modelindex);
3125 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3126 frameblend_t frameblend[MAX_FRAMEBLENDS];
3127 matrix4x4_t blendedmatrix;
3129 PRVM_G_FLOAT(OFS_RETURN) = 0;
3130 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3132 firstbone = max(0, firstbone);
3133 lastbone = min(lastbone, model->num_bones - 1);
3134 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3135 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3136 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3137 blendfrac = 1.0f - retainfrac;
3138 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3139 frameblend[numblends].lerp *= blendfrac;
3140 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3142 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3143 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3144 for (blendindex = 0;blendindex < numblends;blendindex++)
3146 Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3147 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3149 skeleton->relativetransforms[bonenum] = blendedmatrix;
3151 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3154 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3155 static void VM_SV_skel_get_numbones(void)
3157 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3158 skeleton_t *skeleton;
3159 PRVM_G_FLOAT(OFS_RETURN) = 0;
3160 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3162 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3165 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3166 static void VM_SV_skel_get_bonename(void)
3168 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3169 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3170 skeleton_t *skeleton;
3171 PRVM_G_INT(OFS_RETURN) = 0;
3172 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3174 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3176 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3179 // #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)
3180 static void VM_SV_skel_get_boneparent(void)
3182 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3183 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3184 skeleton_t *skeleton;
3185 PRVM_G_FLOAT(OFS_RETURN) = 0;
3186 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3188 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3190 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3193 // #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
3194 static void VM_SV_skel_find_bone(void)
3196 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3197 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3198 skeleton_t *skeleton;
3199 PRVM_G_FLOAT(OFS_RETURN) = 0;
3200 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3202 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3205 // #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)
3206 static void VM_SV_skel_get_bonerel(void)
3208 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3209 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3210 skeleton_t *skeleton;
3212 vec3_t forward, left, up, origin;
3213 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3214 VectorClear(prog->globals.client->v_forward);
3215 VectorClear(prog->globals.client->v_right);
3216 VectorClear(prog->globals.client->v_up);
3217 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3219 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3221 matrix = skeleton->relativetransforms[bonenum];
3222 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3223 VectorCopy(forward, prog->globals.client->v_forward);
3224 VectorNegate(left, prog->globals.client->v_right);
3225 VectorCopy(up, prog->globals.client->v_up);
3226 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3229 // #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)
3230 static void VM_SV_skel_get_boneabs(void)
3232 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3233 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3234 skeleton_t *skeleton;
3237 vec3_t forward, left, up, origin;
3238 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3239 VectorClear(prog->globals.client->v_forward);
3240 VectorClear(prog->globals.client->v_right);
3241 VectorClear(prog->globals.client->v_up);
3242 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3244 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3246 matrix = skeleton->relativetransforms[bonenum];
3247 // convert to absolute
3248 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3251 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3253 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3254 VectorCopy(forward, prog->globals.client->v_forward);
3255 VectorNegate(left, prog->globals.client->v_right);
3256 VectorCopy(up, prog->globals.client->v_up);
3257 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3260 // #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)
3261 static void VM_SV_skel_set_bone(void)
3263 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3264 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3265 vec3_t forward, left, up, origin;
3266 skeleton_t *skeleton;
3268 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3270 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3272 VectorCopy(prog->globals.client->v_forward, forward);
3273 VectorNegate(prog->globals.client->v_right, left);
3274 VectorCopy(prog->globals.client->v_up, up);
3275 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3276 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3277 skeleton->relativetransforms[bonenum] = matrix;
3280 // #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)
3281 static void VM_SV_skel_mul_bone(void)
3283 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3284 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3285 vec3_t forward, left, up, origin;
3286 skeleton_t *skeleton;
3289 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3291 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3293 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3294 VectorCopy(prog->globals.client->v_forward, forward);
3295 VectorNegate(prog->globals.client->v_right, left);
3296 VectorCopy(prog->globals.client->v_up, up);
3297 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3298 temp = skeleton->relativetransforms[bonenum];
3299 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3302 // #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)
3303 static void VM_SV_skel_mul_bones(void)
3305 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3306 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3307 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3309 vec3_t forward, left, up, origin;
3310 skeleton_t *skeleton;
3313 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3315 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3316 VectorCopy(prog->globals.client->v_forward, forward);
3317 VectorNegate(prog->globals.client->v_right, left);
3318 VectorCopy(prog->globals.client->v_up, up);
3319 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3320 firstbone = max(0, firstbone);
3321 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3322 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3324 temp = skeleton->relativetransforms[bonenum];
3325 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3329 // #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
3330 static void VM_SV_skel_copybones(void)
3332 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3333 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3334 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3335 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3337 skeleton_t *skeletondst;
3338 skeleton_t *skeletonsrc;
3339 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3341 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3343 firstbone = max(0, firstbone);
3344 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3345 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3346 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3347 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3350 // #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)
3351 static void VM_SV_skel_delete(void)
3353 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3354 skeleton_t *skeleton;
3355 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3358 prog->skeletons[skeletonindex] = NULL;
3361 // #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
3362 static void VM_SV_frameforname(void)
3364 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3365 dp_model_t *model = SV_GetModelByIndex(modelindex);
3366 const char *name = PRVM_G_STRING(OFS_PARM1);
3368 PRVM_G_FLOAT(OFS_RETURN) = -1;
3369 if (!model || !model->animscenes)
3371 for (i = 0;i < model->numframes;i++)
3373 if (!strcasecmp(model->animscenes[i].name, name))
3375 PRVM_G_FLOAT(OFS_RETURN) = i;
3381 // #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.
3382 static void VM_SV_frameduration(void)
3384 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3385 dp_model_t *model = SV_GetModelByIndex(modelindex);
3386 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3387 PRVM_G_FLOAT(OFS_RETURN) = 0;
3388 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3390 if (model->animscenes[framenum].framerate)
3391 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3395 prvm_builtin_t vm_sv_builtins[] = {
3396 NULL, // #0 NULL function (not callable) (QUAKE)
3397 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3398 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3399 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3400 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3401 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3402 VM_break, // #6 void() break (QUAKE)
3403 VM_random, // #7 float() random (QUAKE)
3404 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3405 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3406 VM_error, // #10 void(string e) error (QUAKE)
3407 VM_objerror, // #11 void(string e) objerror (QUAKE)
3408 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3409 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3410 VM_spawn, // #14 entity() spawn (QUAKE)
3411 VM_remove, // #15 void(entity e) remove (QUAKE)
3412 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3413 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3414 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3415 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3416 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3417 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3418 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3419 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3420 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3421 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3422 VM_ftos, // #26 string(float f) ftos (QUAKE)
3423 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3424 VM_coredump, // #28 void() coredump (QUAKE)
3425 VM_traceon, // #29 void() traceon (QUAKE)
3426 VM_traceoff, // #30 void() traceoff (QUAKE)
3427 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3428 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3429 NULL, // #33 (QUAKE)
3430 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3431 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3432 VM_rint, // #36 float(float v) rint (QUAKE)
3433 VM_floor, // #37 float(float v) floor (QUAKE)
3434 VM_ceil, // #38 float(float v) ceil (QUAKE)
3435 NULL, // #39 (QUAKE)
3436 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3437 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3438 NULL, // #42 (QUAKE)
3439 VM_fabs, // #43 float(float f) fabs (QUAKE)
3440 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3441 VM_cvar, // #45 float(string s) cvar (QUAKE)
3442 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3443 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3444 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3445 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3446 NULL, // #50 (QUAKE)
3447 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3448 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3449 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3450 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3451 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3452 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3453 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3454 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3455 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3456 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3457 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3458 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3459 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3460 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3461 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3462 NULL, // #66 (QUAKE)
3463 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3464 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3465 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3466 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3467 NULL, // #71 (QUAKE)
3468 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3469 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3470 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3471 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3472 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3473 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3474 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3475 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3476 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3477 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3478 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3479 NULL, // #83 (QUAKE)
3480 NULL, // #84 (QUAKE)
3481 NULL, // #85 (QUAKE)
3482 NULL, // #86 (QUAKE)
3483 NULL, // #87 (QUAKE)
3484 NULL, // #88 (QUAKE)
3485 NULL, // #89 (QUAKE)
3486 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3487 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3488 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3489 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3490 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3491 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3492 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3493 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3494 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3495 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3496 // FrikaC and Telejano range #100-#199
3507 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3508 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3509 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3510 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3511 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3512 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3513 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3514 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3515 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3516 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3597 // FTEQW range #200-#299
3616 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3619 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3620 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3621 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3622 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3623 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3624 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3625 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3626 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3627 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3628 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3630 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3638 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3661 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.
3662 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
3663 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3664 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3665 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)
3666 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
3667 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)
3668 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)
3669 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)
3670 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)
3671 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)
3672 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
3673 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)
3674 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
3675 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.
3698 // CSQC range #300-#399
3699 NULL, // #300 void() clearscene (EXT_CSQC)
3700 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3701 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3702 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3703 NULL, // #304 void() renderscene (EXT_CSQC)
3704 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3705 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3706 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3707 NULL, // #308 void() R_EndPolygon
3709 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3710 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3714 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3715 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3716 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3717 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3718 NULL, // #319 void(string name) freepic (EXT_CSQC)
3719 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3720 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3721 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3722 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3723 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3724 NULL, // #325 void(void) drawresetcliparea
3729 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3730 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3731 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3732 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3733 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3734 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3735 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3736 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3737 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3738 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3739 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3740 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3741 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3742 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3743 NULL, // #344 vector() getmousepos (EXT_CSQC)
3744 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3745 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3746 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3747 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3748 NULL, // #349 float() isdemo (EXT_CSQC)
3749 VM_isserver, // #350 float() isserver (EXT_CSQC)
3750 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3751 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3752 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3753 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3759 NULL, // #360 float() readbyte (EXT_CSQC)
3760 NULL, // #361 float() readchar (EXT_CSQC)
3761 NULL, // #362 float() readshort (EXT_CSQC)
3762 NULL, // #363 float() readlong (EXT_CSQC)
3763 NULL, // #364 float() readcoord (EXT_CSQC)
3764 NULL, // #365 float() readangle (EXT_CSQC)
3765 NULL, // #366 string() readstring (EXT_CSQC)
3766 NULL, // #367 float() readfloat (EXT_CSQC)
3799 // LordHavoc's range #400-#499
3800 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3801 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3802 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3803 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3804 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3805 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3806 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3807 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3808 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)
3809 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3810 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3811 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3812 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3813 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3814 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3815 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3816 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3817 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3818 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3819 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3820 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3821 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3822 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3823 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3824 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3825 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3826 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3827 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3828 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3829 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3830 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3831 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3832 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3833 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3834 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3835 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3836 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3837 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3838 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3839 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3840 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3841 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3842 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3843 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3844 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3845 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3846 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3847 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3848 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3849 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3850 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3851 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3852 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3853 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3854 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3855 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3856 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3857 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3859 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3860 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3861 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3862 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3863 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3864 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3865 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3866 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3867 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3868 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3869 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3871 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3872 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3873 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3874 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3875 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3876 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3877 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3878 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3879 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3880 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3881 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3882 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3883 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3884 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3885 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3886 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3894 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3895 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3896 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3897 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3898 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3899 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3900 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3901 VM_SV_WritePicture, // #501
3903 VM_whichpack, // #503 string(string) whichpack = #503;
3910 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3911 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3912 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3913 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3914 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3915 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3916 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3917 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3918 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3919 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3929 VM_loadfromdata, // #529
3930 VM_loadfromfile, // #530
3931 VM_SV_setpause, // #531 void(float pause) setpause = #531;
4005 VM_callfunction, // #605
4006 VM_writetofile, // #606
4007 VM_isfunction, // #607
4013 VM_parseentitydata, // #613
4024 VM_SV_getextresponse, // #624 string getextresponse(void)
4028 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4030 void VM_SV_Cmd_Init(void)
4035 void VM_SV_Cmd_Reset(void)
4037 World_End(&sv.world);
4038 if(prog->funcoffsets.SV_Shutdown)
4040 func_t s = prog->funcoffsets.SV_Shutdown;
4041 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4042 PRVM_ExecuteProgram(s,"SV_Shutdown() required");