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));
1402 static void VM_SV_WriteEntity (void)
1404 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1405 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1408 // writes a picture as at most size bytes of data
1410 // IMGNAME \0 SIZE(short) IMGDATA
1411 // if failed to read/compress:
1413 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1414 static void VM_SV_WritePicture (void)
1416 const char *imgname;
1420 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1422 imgname = PRVM_G_STRING(OFS_PARM1);
1423 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1427 MSG_WriteString(WriteDest(), imgname);
1428 if(Image_Compress(imgname, size, &buf, &size))
1431 MSG_WriteShort(WriteDest(), size);
1432 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1437 MSG_WriteShort(WriteDest(), 0);
1441 //////////////////////////////////////////////////////////
1443 static void VM_SV_makestatic (void)
1448 // allow 0 parameters due to an id1 qc bug in which this function is used
1449 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1450 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1452 if (prog->argc >= 1)
1453 ent = PRVM_G_EDICT(OFS_PARM0);
1455 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1456 if (ent == prog->edicts)
1458 VM_Warning("makestatic: can not modify world entity\n");
1461 if (ent->priv.server->free)
1463 VM_Warning("makestatic: can not modify free entity\n");
1468 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1473 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1474 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1475 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1477 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1479 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1480 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1481 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1485 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1486 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1487 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1490 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1491 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1492 for (i=0 ; i<3 ; i++)
1494 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1495 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1498 // throw the entity away now
1502 //=============================================================================
1509 static void VM_SV_setspawnparms (void)
1515 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1517 ent = PRVM_G_EDICT(OFS_PARM0);
1518 i = PRVM_NUM_FOR_EDICT(ent);
1519 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1521 Con_Print("tried to setspawnparms on a non-client\n");
1525 // copy spawn parms out of the client_t
1526 client = svs.clients + i-1;
1527 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1528 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1535 Returns a color vector indicating the lighting at the requested point.
1537 (Internal Operation note: actually measures the light beneath the point, just like
1538 the model lighting on the client)
1543 static void VM_SV_getlight (void)
1545 vec3_t ambientcolor, diffusecolor, diffusenormal;
1547 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1548 p = PRVM_G_VECTOR(OFS_PARM0);
1549 VectorClear(ambientcolor);
1550 VectorClear(diffusecolor);
1551 VectorClear(diffusenormal);
1552 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1553 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1554 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1559 unsigned char type; // 1/2/8 or other value if isn't used
1563 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1564 static int vm_customstats_last;
1566 void VM_CustomStats_Clear (void)
1570 Z_Free(vm_customstats);
1571 vm_customstats = NULL;
1572 vm_customstats_last = -1;
1576 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1584 for(i=0; i<vm_customstats_last+1 ;i++)
1586 if(!vm_customstats[i].type)
1588 switch(vm_customstats[i].type)
1590 //string as 16 bytes
1593 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1594 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1595 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1596 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1597 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1599 //float field sent as-is
1601 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1603 //integer value of float field
1605 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1613 // void(float index, float type, .void field) SV_AddStat = #232;
1614 // Set up an auto-sent player stat.
1615 // Client's get thier own fields sent to them. Index may not be less than 32.
1616 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1617 // 1: string (4 stats carrying a total of 16 charactures)
1618 // 2: float (one stat, float converted to an integer for transportation)
1619 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1620 static void VM_SV_AddStat (void)
1625 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1629 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1632 VM_Warning("PF_SV_AddStat: not enough memory\n");
1636 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1637 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1638 off = PRVM_G_INT (OFS_PARM2);
1643 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1646 if(i >= (MAX_CL_STATS-32))
1648 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1651 if(i > (MAX_CL_STATS-32-4) && type == 1)
1653 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1656 vm_customstats[i].type = type;
1657 vm_customstats[i].fieldoffset = off;
1658 if(vm_customstats_last < i)
1659 vm_customstats_last = i;
1666 copies data from one entity to another
1668 copyentity(src, dst)
1671 static void VM_SV_copyentity (void)
1673 prvm_edict_t *in, *out;
1674 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1675 in = PRVM_G_EDICT(OFS_PARM0);
1676 if (in == prog->edicts)
1678 VM_Warning("copyentity: can not read world entity\n");
1681 if (in->priv.server->free)
1683 VM_Warning("copyentity: can not read free entity\n");
1686 out = PRVM_G_EDICT(OFS_PARM1);
1687 if (out == prog->edicts)
1689 VM_Warning("copyentity: can not modify world entity\n");
1692 if (out->priv.server->free)
1694 VM_Warning("copyentity: can not modify free entity\n");
1697 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1706 sets the color of a client and broadcasts the update to all connected clients
1708 setcolor(clientent, value)
1711 static void VM_SV_setcolor (void)
1717 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1718 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1719 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1721 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1723 Con_Print("tried to setcolor a non-client\n");
1727 client = svs.clients + entnum-1;
1730 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1732 client->edict->fields.server->team = (i & 15) + 1;
1735 if (client->old_colors != client->colors)
1737 client->old_colors = client->colors;
1738 // send notification to all clients
1739 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1740 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1741 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1749 effect(origin, modelname, startframe, framecount, framerate)
1752 static void VM_SV_effect (void)
1756 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1757 s = PRVM_G_STRING(OFS_PARM1);
1760 VM_Warning("effect: no model specified\n");
1764 i = SV_ModelIndex(s, 1);
1767 VM_Warning("effect: model not precached\n");
1771 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1773 VM_Warning("effect: framecount < 1\n");
1777 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1779 VM_Warning("effect: framerate < 1\n");
1783 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));
1786 static void VM_SV_te_blood (void)
1788 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1789 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1791 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1792 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1794 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1795 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1796 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1798 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1799 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1800 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1802 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1803 SV_FlushBroadcastMessages();
1806 static void VM_SV_te_bloodshower (void)
1808 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1809 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1811 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1812 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1814 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1815 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1816 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1818 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1819 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1820 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1822 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1824 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1825 SV_FlushBroadcastMessages();
1828 static void VM_SV_te_explosionrgb (void)
1830 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1831 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1832 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1834 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1835 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1836 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1838 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1839 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1840 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1841 SV_FlushBroadcastMessages();
1844 static void VM_SV_te_particlecube (void)
1846 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1847 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1849 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1850 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1852 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1853 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1854 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1856 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1857 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1858 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1860 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1861 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1862 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1864 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1866 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1867 // gravity true/false
1868 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1870 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1871 SV_FlushBroadcastMessages();
1874 static void VM_SV_te_particlerain (void)
1876 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1877 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1879 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1880 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1882 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1886 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1887 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1888 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1890 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1891 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1892 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1894 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1896 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1897 SV_FlushBroadcastMessages();
1900 static void VM_SV_te_particlesnow (void)
1902 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1903 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1905 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1906 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1908 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1909 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1912 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1913 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1914 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1916 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1917 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1918 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1920 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1922 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1923 SV_FlushBroadcastMessages();
1926 static void VM_SV_te_spark (void)
1928 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1929 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1931 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1932 MSG_WriteByte(&sv.datagram, TE_SPARK);
1934 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1935 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1936 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1938 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1939 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1940 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1942 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1943 SV_FlushBroadcastMessages();
1946 static void VM_SV_te_gunshotquad (void)
1948 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1949 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1950 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1952 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1953 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1954 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1955 SV_FlushBroadcastMessages();
1958 static void VM_SV_te_spikequad (void)
1960 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
1961 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1962 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1964 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1965 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1966 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1967 SV_FlushBroadcastMessages();
1970 static void VM_SV_te_superspikequad (void)
1972 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
1973 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1974 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
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_explosionquad (void)
1984 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
1985 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1986 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
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_smallflash (void)
1996 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
1997 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1998 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
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_customflash (void)
2008 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2009 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2011 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2012 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2014 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2015 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2016 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2018 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2020 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2022 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2023 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2024 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2025 SV_FlushBroadcastMessages();
2028 static void VM_SV_te_gunshot (void)
2030 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2031 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2032 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2034 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2035 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2036 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2037 SV_FlushBroadcastMessages();
2040 static void VM_SV_te_spike (void)
2042 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2043 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2044 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2046 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2047 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2048 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2049 SV_FlushBroadcastMessages();
2052 static void VM_SV_te_superspike (void)
2054 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2055 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2056 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
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_explosion (void)
2066 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2067 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2068 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
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_tarexplosion (void)
2078 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2079 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2080 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
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_wizspike (void)
2090 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2091 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2092 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
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_knightspike (void)
2102 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2103 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2104 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
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_lavasplash (void)
2114 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2115 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2116 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
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_teleport (void)
2126 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2127 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2128 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
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_explosion2 (void)
2138 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2139 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2140 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
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);
2146 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2147 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2148 SV_FlushBroadcastMessages();
2151 static void VM_SV_te_lightning1 (void)
2153 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2154 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2155 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2157 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2159 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2160 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2161 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2163 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2164 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2165 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2166 SV_FlushBroadcastMessages();
2169 static void VM_SV_te_lightning2 (void)
2171 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2172 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2173 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2175 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2177 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2178 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2179 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2181 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2182 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2184 SV_FlushBroadcastMessages();
2187 static void VM_SV_te_lightning3 (void)
2189 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2190 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2191 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2193 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2195 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2196 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2197 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2199 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2200 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2201 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2202 SV_FlushBroadcastMessages();
2205 static void VM_SV_te_beam (void)
2207 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2208 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2209 MSG_WriteByte(&sv.datagram, TE_BEAM);
2211 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2213 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2214 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2215 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2217 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2218 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2220 SV_FlushBroadcastMessages();
2223 static void VM_SV_te_plasmaburn (void)
2225 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2226 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2227 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2228 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2229 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2230 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2231 SV_FlushBroadcastMessages();
2234 static void VM_SV_te_flamejet (void)
2236 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2237 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2238 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2240 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2244 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2245 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2246 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2248 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2249 SV_FlushBroadcastMessages();
2252 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2255 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2257 bestdist = 1000000000;
2259 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2261 // clip original point to each triangle of the surface and find the
2262 // triangle that is closest
2263 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2264 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2265 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2266 TriangleNormal(v[0], v[1], v[2], facenormal);
2267 VectorNormalize(facenormal);
2268 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2269 VectorMA(p, offsetdist, facenormal, temp);
2270 for (j = 0, k = 2;j < 3;k = j, j++)
2272 VectorSubtract(v[k], v[j], edgenormal);
2273 CrossProduct(edgenormal, facenormal, sidenormal);
2274 VectorNormalize(sidenormal);
2275 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2277 VectorMA(temp, offsetdist, sidenormal, temp);
2279 dist = VectorDistance2(temp, p);
2280 if (bestdist > dist)
2283 VectorCopy(temp, out);
2288 #define getmodel SV_GetModelFromEdict
2290 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2292 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2294 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2298 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2299 static void VM_SV_getsurfacenumpoints(void)
2302 msurface_t *surface;
2303 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2304 // return 0 if no such surface
2305 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2307 PRVM_G_FLOAT(OFS_RETURN) = 0;
2311 // note: this (incorrectly) assumes it is a simple polygon
2312 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2314 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2315 static void VM_SV_getsurfacepoint(void)
2319 msurface_t *surface;
2321 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2322 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2323 ed = PRVM_G_EDICT(OFS_PARM0);
2324 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2326 // note: this (incorrectly) assumes it is a simple polygon
2327 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2328 if (pointnum < 0 || pointnum >= surface->num_vertices)
2330 // FIXME: implement rotation/scaling
2331 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2333 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2334 // float SPA_POSITION = 0;
2335 // float SPA_S_AXIS = 1;
2336 // float SPA_T_AXIS = 2;
2337 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2338 // float SPA_TEXCOORDS0 = 4;
2339 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2340 // float SPA_LIGHTMAP0_COLOR = 6;
2341 static void VM_SV_getsurfacepointattribute(void)
2345 msurface_t *surface;
2349 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2350 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2351 ed = PRVM_G_EDICT(OFS_PARM0);
2352 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2354 // note: this (incorrectly) assumes it is a simple polygon
2355 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2356 if (pointnum < 0 || pointnum >= surface->num_vertices)
2358 // FIXME: implement rotation/scaling
2359 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2361 switch( attributetype ) {
2362 // float SPA_POSITION = 0;
2364 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2366 // float SPA_S_AXIS = 1;
2368 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2370 // float SPA_T_AXIS = 2;
2372 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2374 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2376 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2378 // float SPA_TEXCOORDS0 = 4;
2380 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2381 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2382 ret[0] = texcoord[0];
2383 ret[1] = texcoord[1];
2387 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2389 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2390 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2391 ret[0] = texcoord[0];
2392 ret[1] = texcoord[1];
2396 // float SPA_LIGHTMAP0_COLOR = 6;
2398 // ignore alpha for now..
2399 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2402 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2406 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2407 static void VM_SV_getsurfacenormal(void)
2410 msurface_t *surface;
2412 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2413 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2414 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2416 // FIXME: implement rotation/scaling
2417 // note: this (incorrectly) assumes it is a simple polygon
2418 // note: this only returns the first triangle, so it doesn't work very
2419 // well for curved surfaces or arbitrary meshes
2420 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);
2421 VectorNormalize(normal);
2422 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2424 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2425 static void VM_SV_getsurfacetexture(void)
2428 msurface_t *surface;
2429 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2430 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2431 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2433 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2435 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2436 static void VM_SV_getsurfacenearpoint(void)
2438 int surfacenum, best;
2440 vec_t dist, bestdist;
2443 msurface_t *surface;
2445 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2446 PRVM_G_FLOAT(OFS_RETURN) = -1;
2447 ed = PRVM_G_EDICT(OFS_PARM0);
2448 point = PRVM_G_VECTOR(OFS_PARM1);
2450 if (!ed || ed->priv.server->free)
2452 model = getmodel(ed);
2453 if (!model || !model->num_surfaces)
2456 // FIXME: implement rotation/scaling
2457 VectorSubtract(point, ed->fields.server->origin, p);
2459 bestdist = 1000000000;
2460 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2462 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2463 // first see if the nearest point on the surface's box is closer than the previous match
2464 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2465 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2466 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2467 dist = VectorLength2(clipped);
2468 if (dist < bestdist)
2470 // it is, check the nearest point on the actual geometry
2471 clippointtosurface(model, surface, p, clipped);
2472 VectorSubtract(clipped, p, clipped);
2473 dist += VectorLength2(clipped);
2474 if (dist < bestdist)
2476 // that's closer too, store it as the best match
2482 PRVM_G_FLOAT(OFS_RETURN) = best;
2484 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2485 static void VM_SV_getsurfaceclippedpoint(void)
2489 msurface_t *surface;
2491 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2492 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2493 ed = PRVM_G_EDICT(OFS_PARM0);
2494 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2496 // FIXME: implement rotation/scaling
2497 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2498 clippointtosurface(model, surface, p, out);
2499 // FIXME: implement rotation/scaling
2500 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2503 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2504 //this function originally written by KrimZon, made shorter by LordHavoc
2505 static void VM_SV_clientcommand (void)
2507 client_t *temp_client;
2509 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2511 //find client for this entity
2512 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2513 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2515 Con_Print("PF_clientcommand: entity is not a client\n");
2519 temp_client = host_client;
2520 host_client = svs.clients + i;
2521 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2522 host_client = temp_client;
2525 //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)
2526 static void VM_SV_setattachment (void)
2528 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2529 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2530 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2533 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2535 if (e == prog->edicts)
2537 VM_Warning("setattachment: can not modify world entity\n");
2540 if (e->priv.server->free)
2542 VM_Warning("setattachment: can not modify free entity\n");
2546 if (tagentity == NULL)
2547 tagentity = prog->edicts;
2549 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2551 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2553 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2556 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2558 model = SV_GetModelFromEdict(tagentity);
2561 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2563 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);
2566 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));
2570 /////////////////////////////////////////
2571 // DP_MD3_TAGINFO extension coded by VorteX
2573 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2577 i = (int)e->fields.server->modelindex;
2578 if (i < 1 || i >= MAX_MODELS)
2581 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2584 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2591 Matrix4x4_CreateIdentity(tag_localmatrix);
2593 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2595 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2606 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2610 float pitchsign = 1;
2613 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2614 if (val && val->_float != 0)
2615 scale = val->_float;
2618 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);
2621 pitchsign = SV_GetPitchSign(ent);
2622 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);
2626 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2629 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->num_bones)
2631 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2632 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2633 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2634 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2636 *out = identitymatrix;
2640 // Warnings/errors code:
2641 // 0 - normal (everything all-right)
2644 // 3 - null or non-precached model
2645 // 4 - no tags with requested index
2646 // 5 - runaway loop at attachment chain
2647 extern cvar_t cl_bob;
2648 extern cvar_t cl_bobcycle;
2649 extern cvar_t cl_bobup;
2650 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2654 int modelindex, attachloop;
2655 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2658 *out = identitymatrix; // warnings and errors return identical matrix
2660 if (ent == prog->edicts)
2662 if (ent->priv.server->free)
2665 modelindex = (int)ent->fields.server->modelindex;
2666 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2669 model = SV_GetModelByIndex(modelindex);
2671 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2672 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2673 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2675 tagmatrix = identitymatrix;
2676 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2680 if (attachloop >= 256) // prevent runaway looping
2682 // apply transformation by child's tagindex on parent entity and then
2683 // by parent entity itself
2684 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2685 if (ret && attachloop == 0)
2687 SV_GetEntityMatrix(ent, &entitymatrix, false);
2688 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2689 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2690 // next iteration we process the parent entity
2691 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2693 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2694 ent = PRVM_EDICT_NUM(val->edict);
2701 // RENDER_VIEWMODEL magic
2702 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2704 Matrix4x4_Copy(&tagmatrix, out);
2705 ent = PRVM_EDICT_NUM(val->edict);
2707 SV_GetEntityMatrix(ent, &entitymatrix, true);
2708 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2711 // Cl_bob, ported from rendering code
2712 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2715 // LordHavoc: this code is *weird*, but not replacable (I think it
2716 // should be done in QC on the server, but oh well, quake is quake)
2717 // LordHavoc: figured out bobup: the time at which the sin is at 180
2718 // degrees (which allows lengthening or squishing the peak or valley)
2719 cycle = sv.time/cl_bobcycle.value;
2720 cycle -= (int)cycle;
2721 if (cycle < cl_bobup.value)
2722 cycle = sin(M_PI * cycle / cl_bobup.value);
2724 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2725 // bob is proportional to velocity in the xy plane
2726 // (don't count Z, or jumping messes it up)
2727 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;
2728 bob = bob*0.3 + bob*0.7*cycle;
2729 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2736 //float(entity ent, string tagname) gettagindex;
2738 static void VM_SV_gettagindex (void)
2741 const char *tag_name;
2744 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2746 ent = PRVM_G_EDICT(OFS_PARM0);
2747 tag_name = PRVM_G_STRING(OFS_PARM1);
2749 if (ent == prog->edicts)
2751 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2754 if (ent->priv.server->free)
2756 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2761 if (!SV_GetModelFromEdict(ent))
2762 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2765 tag_index = SV_GetTagIndex(ent, tag_name);
2767 if(developer.integer >= 100)
2768 Con_Printf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2770 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2773 //vector(entity ent, float tagindex) gettaginfo;
2774 static void VM_SV_gettaginfo (void)
2778 matrix4x4_t tag_matrix;
2779 matrix4x4_t tag_localmatrix;
2781 const char *tagname;
2784 vec3_t fo, le, up, trans;
2785 const dp_model_t *model;
2787 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2789 e = PRVM_G_EDICT(OFS_PARM0);
2790 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2792 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2793 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2794 VectorScale(le, -1, prog->globals.server->v_right);
2795 model = SV_GetModelFromEdict(e);
2796 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2797 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2798 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2799 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2800 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2802 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2803 val->_float = parentindex;
2804 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2805 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2806 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2807 VectorCopy(trans, val->vector);
2808 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2809 VectorCopy(fo, val->vector);
2810 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2811 VectorScale(le, -1, val->vector);
2812 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2813 VectorCopy(up, val->vector);
2818 VM_Warning("gettagindex: can't affect world entity\n");
2821 VM_Warning("gettagindex: can't affect free entity\n");
2824 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2827 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2830 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2835 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2836 static void VM_SV_dropclient (void)
2839 client_t *oldhostclient;
2840 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2841 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2842 if (clientnum < 0 || clientnum >= svs.maxclients)
2844 VM_Warning("dropclient: not a client\n");
2847 if (!svs.clients[clientnum].active)
2849 VM_Warning("dropclient: that client slot is not connected\n");
2852 oldhostclient = host_client;
2853 host_client = svs.clients + clientnum;
2854 SV_DropClient(false);
2855 host_client = oldhostclient;
2858 //entity() spawnclient (DP_SV_BOTCLIENT)
2859 static void VM_SV_spawnclient (void)
2863 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2864 prog->xfunction->builtinsprofile += 2;
2866 for (i = 0;i < svs.maxclients;i++)
2868 if (!svs.clients[i].active)
2870 prog->xfunction->builtinsprofile += 100;
2871 SV_ConnectClient (i, NULL);
2872 // this has to be set or else ClientDisconnect won't be called
2873 // we assume the qc will call ClientConnect...
2874 svs.clients[i].clientconnectcalled = true;
2875 ed = PRVM_EDICT_NUM(i + 1);
2879 VM_RETURN_EDICT(ed);
2882 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2883 static void VM_SV_clienttype (void)
2886 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2887 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2888 if (clientnum < 0 || clientnum >= svs.maxclients)
2889 PRVM_G_FLOAT(OFS_RETURN) = 3;
2890 else if (!svs.clients[clientnum].active)
2891 PRVM_G_FLOAT(OFS_RETURN) = 0;
2892 else if (svs.clients[clientnum].netconnection)
2893 PRVM_G_FLOAT(OFS_RETURN) = 1;
2895 PRVM_G_FLOAT(OFS_RETURN) = 2;
2902 string(string key) serverkey
2905 void VM_SV_serverkey(void)
2907 char string[VM_STRINGTEMP_LENGTH];
2908 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2909 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2910 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2913 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2914 static void VM_SV_setmodelindex (void)
2919 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2921 e = PRVM_G_EDICT(OFS_PARM0);
2922 if (e == prog->edicts)
2924 VM_Warning("setmodelindex: can not modify world entity\n");
2927 if (e->priv.server->free)
2929 VM_Warning("setmodelindex: can not modify free entity\n");
2932 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2933 if (i <= 0 || i >= MAX_MODELS)
2935 VM_Warning("setmodelindex: invalid modelindex\n");
2938 if (!sv.model_precache[i][0])
2940 VM_Warning("setmodelindex: model not precached\n");
2944 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2945 e->fields.server->modelindex = i;
2947 mod = SV_GetModelByIndex(i);
2951 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2952 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2954 SetMinMaxSize (e, quakemins, quakemaxs, true);
2957 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
2960 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2961 static void VM_SV_modelnameforindex (void)
2964 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2966 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2968 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2969 if (i <= 0 || i >= MAX_MODELS)
2971 VM_Warning("modelnameforindex: invalid modelindex\n");
2974 if (!sv.model_precache[i][0])
2976 VM_Warning("modelnameforindex: model not precached\n");
2980 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
2983 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2984 static void VM_SV_particleeffectnum (void)
2987 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2988 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2991 PRVM_G_FLOAT(OFS_RETURN) = i;
2994 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2995 static void VM_SV_trailparticles (void)
2997 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2999 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3002 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3003 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3004 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3005 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3006 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3007 SV_FlushBroadcastMessages();
3010 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3011 static void VM_SV_pointparticles (void)
3013 int effectnum, count;
3015 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3017 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3020 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3021 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3022 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3023 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3024 if (count == 1 && !VectorLength2(vel))
3027 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3028 MSG_WriteShort(&sv.datagram, effectnum);
3029 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3033 // 1+2+12+12+2=29 bytes
3034 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3035 MSG_WriteShort(&sv.datagram, effectnum);
3036 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3037 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3038 MSG_WriteShort(&sv.datagram, count);
3041 SV_FlushBroadcastMessages();
3044 //PF_setpause, // void(float pause) setpause = #531;
3045 static void VM_SV_setpause(void) {
3047 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3048 if (pauseValue != 0) { //pause the game
3050 sv.pausedstart = Sys_DoubleTime();
3051 } else { //disable pause, in case it was enabled
3052 if (sv.paused != 0) {
3057 // send notification to all clients
3058 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3059 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3062 // #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.
3063 static void VM_SV_skel_create(void)
3065 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3066 dp_model_t *model = SV_GetModelByIndex(modelindex);
3067 skeleton_t *skeleton;
3069 PRVM_G_FLOAT(OFS_RETURN) = 0;
3070 if (!model || !model->num_bones)
3072 for (i = 0;i < MAX_EDICTS;i++)
3073 if (!prog->skeletons[i])
3075 if (i == MAX_EDICTS)
3077 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3078 skeleton->model = model;
3079 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3080 // initialize to identity matrices
3081 for (i = 0;i < skeleton->model->num_bones;i++)
3082 skeleton->relativetransforms[i] = identitymatrix;
3083 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3086 // #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
3087 static void VM_SV_skel_build(void)
3089 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3090 skeleton_t *skeleton;
3091 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3092 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3093 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3094 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3095 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3096 dp_model_t *model = SV_GetModelByIndex(modelindex);
3101 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3102 frameblend_t frameblend[MAX_FRAMEBLENDS];
3103 matrix4x4_t blendedmatrix;
3105 PRVM_G_FLOAT(OFS_RETURN) = 0;
3106 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3108 firstbone = max(0, firstbone);
3109 lastbone = min(lastbone, model->num_bones - 1);
3110 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3111 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3112 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3113 blendfrac = 1.0f - retainfrac;
3114 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3115 frameblend[numblends].lerp *= blendfrac;
3116 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3118 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3119 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3120 for (blendindex = 0;blendindex < numblends;blendindex++)
3122 Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3123 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3125 skeleton->relativetransforms[bonenum] = blendedmatrix;
3127 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3130 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3131 static void VM_SV_skel_get_numbones(void)
3133 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3134 skeleton_t *skeleton;
3135 PRVM_G_FLOAT(OFS_RETURN) = 0;
3136 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3138 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3141 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3142 static void VM_SV_skel_get_bonename(void)
3144 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3145 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3146 skeleton_t *skeleton;
3147 PRVM_G_INT(OFS_RETURN) = 0;
3148 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3150 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3152 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3155 // #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)
3156 static void VM_SV_skel_get_boneparent(void)
3158 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3159 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3160 skeleton_t *skeleton;
3161 PRVM_G_FLOAT(OFS_RETURN) = 0;
3162 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3164 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3166 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3169 // #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
3170 static void VM_SV_skel_find_bone(void)
3172 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3173 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3174 skeleton_t *skeleton;
3175 PRVM_G_FLOAT(OFS_RETURN) = 0;
3176 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3178 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3181 // #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)
3182 static void VM_SV_skel_get_bonerel(void)
3184 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3185 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3186 skeleton_t *skeleton;
3188 vec3_t forward, left, up, origin;
3189 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3190 VectorClear(prog->globals.client->v_forward);
3191 VectorClear(prog->globals.client->v_right);
3192 VectorClear(prog->globals.client->v_up);
3193 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3195 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3197 matrix = skeleton->relativetransforms[bonenum];
3198 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3199 VectorCopy(forward, prog->globals.client->v_forward);
3200 VectorNegate(left, prog->globals.client->v_right);
3201 VectorCopy(up, prog->globals.client->v_up);
3202 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3205 // #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)
3206 static void VM_SV_skel_get_boneabs(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;
3213 vec3_t forward, left, up, origin;
3214 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3215 VectorClear(prog->globals.client->v_forward);
3216 VectorClear(prog->globals.client->v_right);
3217 VectorClear(prog->globals.client->v_up);
3218 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3220 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3222 matrix = skeleton->relativetransforms[bonenum];
3223 // convert to absolute
3224 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3227 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3229 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3230 VectorCopy(forward, prog->globals.client->v_forward);
3231 VectorNegate(left, prog->globals.client->v_right);
3232 VectorCopy(up, prog->globals.client->v_up);
3233 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3236 // #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)
3237 static void VM_SV_skel_set_bone(void)
3239 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3240 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3241 vec3_t forward, left, up, origin;
3242 skeleton_t *skeleton;
3244 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3246 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3248 VectorCopy(prog->globals.client->v_forward, forward);
3249 VectorNegate(prog->globals.client->v_right, left);
3250 VectorCopy(prog->globals.client->v_up, up);
3251 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3252 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3253 skeleton->relativetransforms[bonenum] = matrix;
3256 // #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)
3257 static void VM_SV_skel_mul_bone(void)
3259 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3260 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3261 vec3_t forward, left, up, origin;
3262 skeleton_t *skeleton;
3265 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3267 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3269 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3270 VectorCopy(prog->globals.client->v_forward, forward);
3271 VectorNegate(prog->globals.client->v_right, left);
3272 VectorCopy(prog->globals.client->v_up, up);
3273 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3274 temp = skeleton->relativetransforms[bonenum];
3275 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3278 // #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)
3279 static void VM_SV_skel_mul_bones(void)
3281 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3282 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3283 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3285 vec3_t forward, left, up, origin;
3286 skeleton_t *skeleton;
3289 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3291 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3292 VectorCopy(prog->globals.client->v_forward, forward);
3293 VectorNegate(prog->globals.client->v_right, left);
3294 VectorCopy(prog->globals.client->v_up, up);
3295 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3296 firstbone = max(0, firstbone);
3297 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3298 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3300 temp = skeleton->relativetransforms[bonenum];
3301 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3305 // #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
3306 static void VM_SV_skel_copybones(void)
3308 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3309 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3310 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3311 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3313 skeleton_t *skeletondst;
3314 skeleton_t *skeletonsrc;
3315 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3317 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3319 firstbone = max(0, firstbone);
3320 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3321 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3322 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3323 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3326 // #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)
3327 static void VM_SV_skel_delete(void)
3329 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3330 skeleton_t *skeleton;
3331 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3334 prog->skeletons[skeletonindex] = NULL;
3337 // #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
3338 static void VM_SV_frameforname(void)
3340 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3341 dp_model_t *model = SV_GetModelByIndex(modelindex);
3342 const char *name = PRVM_G_STRING(OFS_PARM1);
3344 PRVM_G_FLOAT(OFS_RETURN) = -1;
3345 if (!model || !model->animscenes)
3347 for (i = 0;i < model->numframes;i++)
3349 if (!strcasecmp(model->animscenes[i].name, name))
3351 PRVM_G_FLOAT(OFS_RETURN) = i;
3357 // #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.
3358 static void VM_SV_frameduration(void)
3360 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3361 dp_model_t *model = SV_GetModelByIndex(modelindex);
3362 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3363 PRVM_G_FLOAT(OFS_RETURN) = 0;
3364 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3366 if (model->animscenes[framenum].framerate)
3367 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3371 prvm_builtin_t vm_sv_builtins[] = {
3372 NULL, // #0 NULL function (not callable) (QUAKE)
3373 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3374 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3375 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3376 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3377 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3378 VM_break, // #6 void() break (QUAKE)
3379 VM_random, // #7 float() random (QUAKE)
3380 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3381 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3382 VM_error, // #10 void(string e) error (QUAKE)
3383 VM_objerror, // #11 void(string e) objerror (QUAKE)
3384 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3385 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3386 VM_spawn, // #14 entity() spawn (QUAKE)
3387 VM_remove, // #15 void(entity e) remove (QUAKE)
3388 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3389 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3390 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3391 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3392 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3393 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3394 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3395 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3396 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3397 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3398 VM_ftos, // #26 string(float f) ftos (QUAKE)
3399 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3400 VM_coredump, // #28 void() coredump (QUAKE)
3401 VM_traceon, // #29 void() traceon (QUAKE)
3402 VM_traceoff, // #30 void() traceoff (QUAKE)
3403 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3404 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3405 NULL, // #33 (QUAKE)
3406 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3407 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3408 VM_rint, // #36 float(float v) rint (QUAKE)
3409 VM_floor, // #37 float(float v) floor (QUAKE)
3410 VM_ceil, // #38 float(float v) ceil (QUAKE)
3411 NULL, // #39 (QUAKE)
3412 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3413 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3414 NULL, // #42 (QUAKE)
3415 VM_fabs, // #43 float(float f) fabs (QUAKE)
3416 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3417 VM_cvar, // #45 float(string s) cvar (QUAKE)
3418 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3419 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3420 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3421 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3422 NULL, // #50 (QUAKE)
3423 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3424 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3425 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3426 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3427 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3428 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3429 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3430 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3431 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3432 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3433 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3434 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3435 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3436 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3437 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3438 NULL, // #66 (QUAKE)
3439 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3440 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3441 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3442 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3443 NULL, // #71 (QUAKE)
3444 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3445 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3446 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3447 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3448 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3449 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3450 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3451 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3452 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3453 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3454 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3455 NULL, // #83 (QUAKE)
3456 NULL, // #84 (QUAKE)
3457 NULL, // #85 (QUAKE)
3458 NULL, // #86 (QUAKE)
3459 NULL, // #87 (QUAKE)
3460 NULL, // #88 (QUAKE)
3461 NULL, // #89 (QUAKE)
3462 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3463 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3464 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3465 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3466 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3467 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3468 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3469 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3470 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3471 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3472 // FrikaC and Telejano range #100-#199
3483 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3484 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3485 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3486 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3487 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3488 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3489 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3490 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3491 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3492 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3573 // FTEQW range #200-#299
3592 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3595 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3596 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3597 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3598 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3599 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3600 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3601 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3602 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3603 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3604 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3606 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3614 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3637 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.
3638 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
3639 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3640 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3641 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)
3642 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
3643 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)
3644 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)
3645 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)
3646 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)
3647 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)
3648 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
3649 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)
3650 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
3651 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.
3674 // CSQC range #300-#399
3675 NULL, // #300 void() clearscene (EXT_CSQC)
3676 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3677 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3678 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3679 NULL, // #304 void() renderscene (EXT_CSQC)
3680 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3681 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3682 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3683 NULL, // #308 void() R_EndPolygon
3685 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3686 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3690 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3691 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3692 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3693 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3694 NULL, // #319 void(string name) freepic (EXT_CSQC)
3695 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3696 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3697 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3698 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3699 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3700 NULL, // #325 void(void) drawresetcliparea
3705 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3706 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3707 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3708 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3709 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3710 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3711 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3712 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3713 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3714 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3715 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3716 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3717 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3718 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3719 NULL, // #344 vector() getmousepos (EXT_CSQC)
3720 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3721 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3722 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3723 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3724 NULL, // #349 float() isdemo (EXT_CSQC)
3725 VM_isserver, // #350 float() isserver (EXT_CSQC)
3726 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3727 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3728 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3729 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3735 NULL, // #360 float() readbyte (EXT_CSQC)
3736 NULL, // #361 float() readchar (EXT_CSQC)
3737 NULL, // #362 float() readshort (EXT_CSQC)
3738 NULL, // #363 float() readlong (EXT_CSQC)
3739 NULL, // #364 float() readcoord (EXT_CSQC)
3740 NULL, // #365 float() readangle (EXT_CSQC)
3741 NULL, // #366 string() readstring (EXT_CSQC)
3742 NULL, // #367 float() readfloat (EXT_CSQC)
3775 // LordHavoc's range #400-#499
3776 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3777 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3778 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3779 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3780 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3781 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3782 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3783 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3784 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)
3785 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3786 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3787 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3788 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3789 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3790 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3791 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3792 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3793 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3794 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3795 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3796 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3797 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3798 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3799 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3800 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3801 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3802 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3803 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3804 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3805 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3806 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3807 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3808 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3809 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3810 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3811 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3812 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3813 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3814 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3815 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3816 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3817 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3818 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3819 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3820 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3821 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3822 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3823 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3824 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3825 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3826 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3827 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3828 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3829 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3830 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3831 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3832 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3833 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3835 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3836 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3837 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3838 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3839 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3840 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3841 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3842 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3843 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3844 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3845 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3847 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3848 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3849 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3850 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3851 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3852 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3853 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3854 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3855 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3856 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3857 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3858 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3859 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3860 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3861 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3862 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3870 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3871 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3872 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3873 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3874 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3875 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3876 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3877 VM_SV_WritePicture, // #501
3879 VM_whichpack, // #503 string(string) whichpack = #503;
3886 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3887 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3888 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3889 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3890 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3891 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3892 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3893 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3894 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3895 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3905 VM_loadfromdata, // #529
3906 VM_loadfromfile, // #530
3907 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3981 VM_callfunction, // #605
3982 VM_writetofile, // #606
3983 VM_isfunction, // #607
3989 VM_parseentitydata, // #613
4000 VM_SV_getextresponse, // #624 string getextresponse(void)
4004 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4006 void VM_SV_Cmd_Init(void)
4011 void VM_SV_Cmd_Reset(void)
4013 World_End(&sv.world);
4014 if(prog->funcoffsets.SV_Shutdown)
4016 func_t s = prog->funcoffsets.SV_Shutdown;
4017 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4018 PRVM_ExecuteProgram(s,"SV_Shutdown() required");