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 "
41 "DP_ENT_CUSTOMCOLORMAP "
42 "DP_ENT_EXTERIORMODELTOCLIENT "
45 "DP_ENT_LOWPRECISION "
49 "DP_GFX_EXTERNALTEXTURES "
50 "DP_GFX_EXTERNALTEXTURES_PERMAP "
52 "DP_GFX_MODEL_INTERPOLATION "
53 "DP_GFX_QUAKE3MODELTAGS "
57 "DP_HALFLIFE_MAP_CVAR "
60 "DP_LIGHTSTYLE_STATICVALUE "
64 "DP_MOVETYPEBOUNCEMISSILE "
67 "DP_QC_ASINACOSATANATAN2TAN "
72 "DP_QC_CVAR_DEFSTRING "
73 "DP_QC_CVAR_DESCRIPTION "
80 "DP_QC_EXTRESPONSEPACKET "
82 "DP_QC_FINDCHAINFLAGS "
83 "DP_QC_FINDCHAINFLOAT "
84 "DP_QC_FINDCHAIN_TOFIELD "
90 "DP_QC_GETSURFACEPOINTATTRIBUTE "
92 "DP_QC_GETTAGINFO_BONEPROPERTIES "
94 "DP_QC_GETTIME_CDTRACK "
97 "DP_QC_MULTIPLETEMPSTRINGS "
98 "DP_QC_NUM_FOR_EDICT "
100 "DP_QC_SINCOSSQRTPOW "
102 "DP_QC_STRINGBUFFERS "
103 "DP_QC_STRINGBUFFERS_CVARLIST "
104 "DP_QC_STRINGCOLORFUNCTIONS "
105 "DP_QC_STRING_CASE_FUNCTIONS "
107 "DP_QC_TOKENIZEBYSEPARATOR "
108 "DP_QC_TOKENIZE_CONSOLE "
111 "DP_QC_TRACE_MOVETYPE_HITMODEL "
112 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
113 "DP_QC_UNLIMITEDTEMPSTRINGS "
116 "DP_QC_VECTOANGLES_WITH_ROLL "
117 "DP_QC_VECTORVECTORS "
124 "DP_SKELETONOBJECTS "
125 "DP_SND_DIRECTIONLESSATTNNONE "
133 "DP_SV_BOUNCEFACTOR "
134 "DP_SV_CLIENTCOLORS "
137 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
138 "DP_SV_DRAWONLYTOCLIENT "
141 "DP_SV_ENTITYCONTENTSTRANSITION "
142 "DP_SV_MODELFLAGS_AS_EFFECTS "
143 "DP_SV_MOVETYPESTEP_LANDEVENT "
145 "DP_SV_NODRAWTOCLIENT "
146 "DP_SV_ONENTITYNOSPAWNFUNCTION "
147 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
149 "DP_SV_PLAYERPHYSICS "
150 "DP_SV_POINTPARTICLES "
152 "DP_SV_PRECACHEANYTIME "
156 "DP_SV_ROTATINGBMODEL "
160 "DP_SV_SPAWNFUNC_PREFIX "
161 "DP_SV_WRITEPICTURE "
162 "DP_SV_WRITEUNTERMINATEDSTRING "
166 "DP_TE_EXPLOSIONRGB "
168 "DP_TE_PARTICLECUBE "
169 "DP_TE_PARTICLERAIN "
170 "DP_TE_PARTICLESNOW "
172 "DP_TE_QUADEFFECTS1 "
175 "DP_TE_STANDARDEFFECTBUILTINS "
176 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
180 "FTE_CSQC_SKELETONOBJECTS "
183 "KRIMZON_SV_PARSECLIENTCOMMAND "
186 "NEXUIZ_PLAYERMODEL "
188 "PRYDON_CLIENTCURSOR "
189 "TENEBRAE_GFX_DLIGHTS "
192 //"EXT_CSQC " // not ready yet
199 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.
201 setorigin (entity, origin)
204 static void VM_SV_setorigin (void)
209 VM_SAFEPARMCOUNT(2, VM_setorigin);
211 e = PRVM_G_EDICT(OFS_PARM0);
212 if (e == prog->edicts)
214 VM_Warning("setorigin: can not modify world entity\n");
217 if (e->priv.server->free)
219 VM_Warning("setorigin: can not modify free entity\n");
222 org = PRVM_G_VECTOR(OFS_PARM1);
223 VectorCopy (org, e->fields.server->origin);
227 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
228 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
232 for (i=0 ; i<3 ; i++)
234 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
236 // set derived values
237 VectorCopy (min, e->fields.server->mins);
238 VectorCopy (max, e->fields.server->maxs);
239 VectorSubtract (max, min, e->fields.server->size);
248 the size box is rotated by the current angle
249 LordHavoc: no it isn't...
251 setsize (entity, minvector, maxvector)
254 static void VM_SV_setsize (void)
259 VM_SAFEPARMCOUNT(3, VM_setsize);
261 e = PRVM_G_EDICT(OFS_PARM0);
262 if (e == prog->edicts)
264 VM_Warning("setsize: can not modify world entity\n");
267 if (e->priv.server->free)
269 VM_Warning("setsize: can not modify free entity\n");
272 min = PRVM_G_VECTOR(OFS_PARM1);
273 max = PRVM_G_VECTOR(OFS_PARM2);
274 SetMinMaxSize (e, min, max, false);
282 setmodel(entity, model)
285 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
286 static void VM_SV_setmodel (void)
292 VM_SAFEPARMCOUNT(2, VM_setmodel);
294 e = PRVM_G_EDICT(OFS_PARM0);
295 if (e == prog->edicts)
297 VM_Warning("setmodel: can not modify world entity\n");
300 if (e->priv.server->free)
302 VM_Warning("setmodel: can not modify free entity\n");
305 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
306 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
307 e->fields.server->modelindex = i;
309 mod = SV_GetModelByIndex(i);
313 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
314 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
316 SetMinMaxSize (e, quakemins, quakemaxs, true);
319 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
326 single print to a specific client
328 sprint(clientent, value)
331 static void VM_SV_sprint (void)
335 char string[VM_STRINGTEMP_LENGTH];
337 VM_VarString(1, string, sizeof(string));
339 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
341 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
342 // LordHavoc: div0 requested that sprintto world operate like print
349 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
351 VM_Warning("tried to centerprint to a non-client\n");
355 client = svs.clients + entnum-1;
356 if (!client->netconnection)
359 MSG_WriteChar(&client->netconnection->message,svc_print);
360 MSG_WriteString(&client->netconnection->message, string);
368 single print to a specific client
370 centerprint(clientent, value)
373 static void VM_SV_centerprint (void)
377 char string[VM_STRINGTEMP_LENGTH];
379 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
381 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
383 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
385 VM_Warning("tried to centerprint to a non-client\n");
389 client = svs.clients + entnum-1;
390 if (!client->netconnection)
393 VM_VarString(1, string, sizeof(string));
394 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
395 MSG_WriteString(&client->netconnection->message, string);
402 particle(origin, color, count)
405 static void VM_SV_particle (void)
411 VM_SAFEPARMCOUNT(4, VM_SV_particle);
413 org = PRVM_G_VECTOR(OFS_PARM0);
414 dir = PRVM_G_VECTOR(OFS_PARM1);
415 color = PRVM_G_FLOAT(OFS_PARM2);
416 count = PRVM_G_FLOAT(OFS_PARM3);
417 SV_StartParticle (org, dir, (int)color, (int)count);
427 static void VM_SV_ambientsound (void)
431 float vol, attenuation;
434 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
436 pos = PRVM_G_VECTOR (OFS_PARM0);
437 samp = PRVM_G_STRING(OFS_PARM1);
438 vol = PRVM_G_FLOAT(OFS_PARM2);
439 attenuation = PRVM_G_FLOAT(OFS_PARM3);
441 // check to see if samp was properly precached
442 soundnum = SV_SoundIndex(samp, 1);
450 // add an svc_spawnambient command to the level signon packet
453 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
455 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
457 MSG_WriteVector(&sv.signon, pos, sv.protocol);
459 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
460 MSG_WriteShort (&sv.signon, soundnum);
462 MSG_WriteByte (&sv.signon, soundnum);
464 MSG_WriteByte (&sv.signon, (int)(vol*255));
465 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
473 Each entity can have eight independant sound sources, like voice,
476 Channel 0 is an auto-allocate channel, the others override anything
477 already running on that entity/channel pair.
479 An attenuation of 0 will play full volume everywhere in the level.
480 Larger attenuations will drop off.
484 static void VM_SV_sound (void)
488 prvm_edict_t *entity;
492 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
494 entity = PRVM_G_EDICT(OFS_PARM0);
495 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
496 sample = PRVM_G_STRING(OFS_PARM2);
497 volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
498 attenuation = PRVM_G_FLOAT(OFS_PARM4);
501 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
505 if (volume < 0 || volume > 255)
507 VM_Warning("SV_StartSound: volume must be in range 0-1\n");
511 if (attenuation < 0 || attenuation > 4)
513 VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
517 if (channel < 0 || channel > 7)
519 VM_Warning("SV_StartSound: channel must be in range 0-7\n");
523 SV_StartSound (entity, channel, sample, volume, attenuation);
530 Follows the same logic as VM_SV_sound, except instead of
531 an entity, an origin for the sound is provided, and channel
532 is omitted (since no entity is being tracked).
536 static void VM_SV_pointsound(void)
543 VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
545 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
546 sample = PRVM_G_STRING(OFS_PARM1);
547 volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
548 attenuation = PRVM_G_FLOAT(OFS_PARM3);
550 if (volume < 0 || volume > 255)
552 VM_Warning("SV_StartPointSound: volume must be in range 0-1\n");
556 if (attenuation < 0 || attenuation > 4)
558 VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
562 SV_StartPointSound (org, sample, volume, attenuation);
569 Used for use tracing and shot targeting
570 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
571 if the tryents flag is set.
573 traceline (vector1, vector2, movetype, ignore)
576 static void VM_SV_traceline (void)
583 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
585 prog->xfunction->builtinsprofile += 30;
587 v1 = PRVM_G_VECTOR(OFS_PARM0);
588 v2 = PRVM_G_VECTOR(OFS_PARM1);
589 move = (int)PRVM_G_FLOAT(OFS_PARM2);
590 ent = PRVM_G_EDICT(OFS_PARM3);
592 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]))
593 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));
595 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
597 VM_SetTraceGlobals(&trace);
605 Used for use tracing and shot targeting
606 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
607 if the tryents flag is set.
609 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
612 // LordHavoc: added this for my own use, VERY useful, similar to traceline
613 static void VM_SV_tracebox (void)
615 float *v1, *v2, *m1, *m2;
620 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
622 prog->xfunction->builtinsprofile += 30;
624 v1 = PRVM_G_VECTOR(OFS_PARM0);
625 m1 = PRVM_G_VECTOR(OFS_PARM1);
626 m2 = PRVM_G_VECTOR(OFS_PARM2);
627 v2 = PRVM_G_VECTOR(OFS_PARM3);
628 move = (int)PRVM_G_FLOAT(OFS_PARM4);
629 ent = PRVM_G_EDICT(OFS_PARM5);
631 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]))
632 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));
634 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
636 VM_SetTraceGlobals(&trace);
639 static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
644 vec3_t original_origin;
645 vec3_t original_velocity;
646 vec3_t original_angles;
647 vec3_t original_avelocity;
651 VectorCopy(tossent->fields.server->origin , original_origin );
652 VectorCopy(tossent->fields.server->velocity , original_velocity );
653 VectorCopy(tossent->fields.server->angles , original_angles );
654 VectorCopy(tossent->fields.server->avelocity, original_avelocity);
656 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
657 if (val != NULL && val->_float != 0)
658 gravity = val->_float;
661 gravity *= sv_gravity.value * 0.025;
663 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
665 SV_CheckVelocity (tossent);
666 tossent->fields.server->velocity[2] -= gravity;
667 VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
668 VectorScale (tossent->fields.server->velocity, 0.05, move);
669 VectorAdd (tossent->fields.server->origin, move, end);
670 trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
671 VectorCopy (trace.endpos, tossent->fields.server->origin);
672 tossent->fields.server->velocity[2] -= gravity;
674 if (trace.fraction < 1)
678 VectorCopy(original_origin , tossent->fields.server->origin );
679 VectorCopy(original_velocity , tossent->fields.server->velocity );
680 VectorCopy(original_angles , tossent->fields.server->angles );
681 VectorCopy(original_avelocity, tossent->fields.server->avelocity);
686 static void VM_SV_tracetoss (void)
690 prvm_edict_t *ignore;
692 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
694 prog->xfunction->builtinsprofile += 600;
696 ent = PRVM_G_EDICT(OFS_PARM0);
697 if (ent == prog->edicts)
699 VM_Warning("tracetoss: can not use world entity\n");
702 ignore = PRVM_G_EDICT(OFS_PARM1);
704 trace = SV_Trace_Toss (ent, ignore);
706 VM_SetTraceGlobals(&trace);
709 //============================================================================
711 static int checkpvsbytes;
712 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
714 static int VM_SV_newcheckclient (int check)
720 // cycle to the next one
722 check = bound(1, check, svs.maxclients);
723 if (check == svs.maxclients)
731 prog->xfunction->builtinsprofile++;
733 if (i == svs.maxclients+1)
735 // look up the client's edict
736 ent = PRVM_EDICT_NUM(i);
737 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
738 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
740 // found a valid client (possibly the same one again)
744 // get the PVS for the entity
745 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
747 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
748 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
757 Returns a client (or object that has a client enemy) that would be a
760 If there is more than one valid option, they are cycled each frame
762 If (self.origin + self.viewofs) is not in the PVS of the current target,
763 it is not returned at all.
768 int c_invis, c_notvis;
769 static void VM_SV_checkclient (void)
771 prvm_edict_t *ent, *self;
774 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
776 // find a new check if on a new frame
777 if (sv.time - sv.lastchecktime >= 0.1)
779 sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
780 sv.lastchecktime = sv.time;
783 // return check if it might be visible
784 ent = PRVM_EDICT_NUM(sv.lastcheck);
785 if (ent->priv.server->free || ent->fields.server->health <= 0)
787 VM_RETURN_EDICT(prog->edicts);
791 // if current entity can't possibly see the check entity, return 0
792 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
793 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
794 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
797 VM_RETURN_EDICT(prog->edicts);
801 // might be able to see it
803 VM_RETURN_EDICT(ent);
806 //============================================================================
812 Checks if an entity is in a point's PVS.
813 Should be fast but can be inexact.
815 float checkpvs(vector viewpos, entity viewee) = #240;
818 static void VM_SV_checkpvs (void)
821 prvm_edict_t *viewee;
826 unsigned char fatpvs[MAX_MAP_LEAFS/8];
829 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
830 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
831 viewee = PRVM_G_EDICT(OFS_PARM1);
833 if(viewee->priv.server->free)
835 VM_Warning("checkpvs: can not check free entity\n");
836 PRVM_G_FLOAT(OFS_RETURN) = 4;
841 if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
843 // no PVS support on this worldmodel... darn
844 PRVM_G_FLOAT(OFS_RETURN) = 3;
847 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
850 // viewpos isn't in any PVS... darn
851 PRVM_G_FLOAT(OFS_RETURN) = 2;
854 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
856 // using fat PVS like FTEQW does (slow)
857 if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
859 // no PVS support on this worldmodel... darn
860 PRVM_G_FLOAT(OFS_RETURN) = 3;
863 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
866 // viewpos isn't in any PVS... darn
867 PRVM_G_FLOAT(OFS_RETURN) = 2;
870 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
879 Sends text over to the client's execution buffer
881 stuffcmd (clientent, value, ...)
884 static void VM_SV_stuffcmd (void)
888 char string[VM_STRINGTEMP_LENGTH];
890 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
892 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
893 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
895 VM_Warning("Can't stuffcmd to a non-client\n");
899 VM_VarString(1, string, sizeof(string));
902 host_client = svs.clients + entnum-1;
903 Host_ClientCommands ("%s", string);
911 Returns a chain of entities that have origins within a spherical area
913 findradius (origin, radius)
916 static void VM_SV_findradius (void)
918 prvm_edict_t *ent, *chain;
919 vec_t radius, radius2;
920 vec3_t org, eorg, mins, maxs;
923 prvm_edict_t *touchedicts[MAX_EDICTS];
926 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
929 chainfield = PRVM_G_INT(OFS_PARM2);
931 chainfield = prog->fieldoffsets.chain;
933 PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
935 chain = (prvm_edict_t *)prog->edicts;
937 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
938 radius = PRVM_G_FLOAT(OFS_PARM1);
939 radius2 = radius * radius;
941 mins[0] = org[0] - (radius + 1);
942 mins[1] = org[1] - (radius + 1);
943 mins[2] = org[2] - (radius + 1);
944 maxs[0] = org[0] + (radius + 1);
945 maxs[1] = org[1] + (radius + 1);
946 maxs[2] = org[2] + (radius + 1);
947 numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
948 if (numtouchedicts > MAX_EDICTS)
950 // this never happens
951 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
952 numtouchedicts = MAX_EDICTS;
954 for (i = 0;i < numtouchedicts;i++)
956 ent = touchedicts[i];
957 prog->xfunction->builtinsprofile++;
958 // Quake did not return non-solid entities but darkplaces does
959 // (note: this is the reason you can't blow up fallen zombies)
960 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
962 // LordHavoc: compare against bounding box rather than center so it
963 // doesn't miss large objects, and use DotProduct instead of Length
964 // for a major speedup
965 VectorSubtract(org, ent->fields.server->origin, eorg);
966 if (sv_gameplayfix_findradiusdistancetobox.integer)
968 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
969 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
970 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
973 VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
974 if (DotProduct(eorg, eorg) < radius2)
976 PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
981 VM_RETURN_EDICT(chain);
984 static void VM_SV_precache_sound (void)
986 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
987 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
990 static void VM_SV_precache_model (void)
992 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
993 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
994 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1001 float(float yaw, float dist[, settrace]) walkmove
1004 static void VM_SV_walkmove (void)
1013 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1015 // assume failure if it returns early
1016 PRVM_G_FLOAT(OFS_RETURN) = 0;
1018 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1019 if (ent == prog->edicts)
1021 VM_Warning("walkmove: can not modify world entity\n");
1024 if (ent->priv.server->free)
1026 VM_Warning("walkmove: can not modify free entity\n");
1029 yaw = PRVM_G_FLOAT(OFS_PARM0);
1030 dist = PRVM_G_FLOAT(OFS_PARM1);
1031 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1033 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1036 yaw = yaw*M_PI*2 / 360;
1038 move[0] = cos(yaw)*dist;
1039 move[1] = sin(yaw)*dist;
1042 // save program state, because SV_movestep may call other progs
1043 oldf = prog->xfunction;
1044 oldself = prog->globals.server->self;
1046 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1049 // restore program state
1050 prog->xfunction = oldf;
1051 prog->globals.server->self = oldself;
1061 static void VM_SV_droptofloor (void)
1067 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1069 // assume failure if it returns early
1070 PRVM_G_FLOAT(OFS_RETURN) = 0;
1072 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1073 if (ent == prog->edicts)
1075 VM_Warning("droptofloor: can not modify world entity\n");
1078 if (ent->priv.server->free)
1080 VM_Warning("droptofloor: can not modify free entity\n");
1084 VectorCopy (ent->fields.server->origin, end);
1087 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1088 SV_UnstickEntity(ent);
1090 trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1091 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1094 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]);
1095 VectorAdd(ent->fields.server->origin, offset, org);
1096 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1097 VectorSubtract(trace.endpos, offset, trace.endpos);
1098 if (trace.startsolid)
1100 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]);
1101 SV_UnstickEntity(ent);
1103 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1104 ent->fields.server->groundentity = 0;
1105 PRVM_G_FLOAT(OFS_RETURN) = 1;
1107 else if (trace.fraction < 1)
1109 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]);
1110 VectorCopy (trace.endpos, ent->fields.server->origin);
1111 SV_UnstickEntity(ent);
1113 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1114 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1115 PRVM_G_FLOAT(OFS_RETURN) = 1;
1116 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1117 ent->priv.server->suspendedinairflag = true;
1122 if (trace.fraction != 1)
1124 if (trace.fraction < 1)
1125 VectorCopy (trace.endpos, ent->fields.server->origin);
1127 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1128 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1129 PRVM_G_FLOAT(OFS_RETURN) = 1;
1130 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1131 ent->priv.server->suspendedinairflag = true;
1140 void(float style, string value) lightstyle
1143 static void VM_SV_lightstyle (void)
1150 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1152 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1153 val = PRVM_G_STRING(OFS_PARM1);
1155 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1156 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
1159 // change the string in sv
1160 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1162 // send message to all clients on this server
1163 if (sv.state != ss_active)
1166 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1168 if (client->active && client->netconnection)
1170 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1171 MSG_WriteChar (&client->netconnection->message,style);
1172 MSG_WriteString (&client->netconnection->message, val);
1182 static void VM_SV_checkbottom (void)
1184 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1185 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1193 static void VM_SV_pointcontents (void)
1195 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1196 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1203 Pick a vector for the player to shoot along
1204 vector aim(entity, missilespeed)
1207 static void VM_SV_aim (void)
1209 prvm_edict_t *ent, *check, *bestent;
1210 vec3_t start, dir, end, bestdir;
1213 float dist, bestdist;
1216 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1218 // assume failure if it returns early
1219 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1220 // if sv_aim is so high it can't possibly accept anything, skip out early
1221 if (sv_aim.value >= 1)
1224 ent = PRVM_G_EDICT(OFS_PARM0);
1225 if (ent == prog->edicts)
1227 VM_Warning("aim: can not use world entity\n");
1230 if (ent->priv.server->free)
1232 VM_Warning("aim: can not use free entity\n");
1235 speed = PRVM_G_FLOAT(OFS_PARM1);
1237 VectorCopy (ent->fields.server->origin, start);
1240 // try sending a trace straight
1241 VectorCopy (prog->globals.server->v_forward, dir);
1242 VectorMA (start, 2048, dir, end);
1243 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1244 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1245 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1247 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1252 // try all possible entities
1253 VectorCopy (dir, bestdir);
1254 bestdist = sv_aim.value;
1257 check = PRVM_NEXT_EDICT(prog->edicts);
1258 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1260 prog->xfunction->builtinsprofile++;
1261 if (check->fields.server->takedamage != DAMAGE_AIM)
1265 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1266 continue; // don't aim at teammate
1267 for (j=0 ; j<3 ; j++)
1268 end[j] = check->fields.server->origin[j]
1269 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1270 VectorSubtract (end, start, dir);
1271 VectorNormalize (dir);
1272 dist = DotProduct (dir, prog->globals.server->v_forward);
1273 if (dist < bestdist)
1274 continue; // to far to turn
1275 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1276 if (tr.ent == check)
1277 { // can shoot at this one
1285 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1286 dist = DotProduct (dir, prog->globals.server->v_forward);
1287 VectorScale (prog->globals.server->v_forward, dist, end);
1289 VectorNormalize (end);
1290 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1294 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1299 ===============================================================================
1303 ===============================================================================
1306 #define MSG_BROADCAST 0 // unreliable to all
1307 #define MSG_ONE 1 // reliable to one (msg_entity)
1308 #define MSG_ALL 2 // reliable to all
1309 #define MSG_INIT 3 // write to the init string
1310 #define MSG_ENTITY 5
1312 sizebuf_t *WriteDest (void)
1318 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1322 return &sv.datagram;
1325 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1326 entnum = PRVM_NUM_FOR_EDICT(ent);
1327 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1329 VM_Warning ("WriteDest: tried to write to non-client\n");
1330 return &sv.reliable_datagram;
1333 return &svs.clients[entnum-1].netconnection->message;
1336 VM_Warning ("WriteDest: bad destination\n");
1338 return &sv.reliable_datagram;
1344 return sv.writeentitiestoclient_msg;
1350 static void VM_SV_WriteByte (void)
1352 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1353 MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1356 static void VM_SV_WriteChar (void)
1358 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1359 MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1362 static void VM_SV_WriteShort (void)
1364 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1365 MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1368 static void VM_SV_WriteLong (void)
1370 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1371 MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1374 static void VM_SV_WriteAngle (void)
1376 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1377 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1380 static void VM_SV_WriteCoord (void)
1382 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1383 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1386 static void VM_SV_WriteString (void)
1388 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1389 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1392 static void VM_SV_WriteUnterminatedString (void)
1394 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1395 MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1399 static void VM_SV_WriteEntity (void)
1401 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1402 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1405 // writes a picture as at most size bytes of data
1407 // IMGNAME \0 SIZE(short) IMGDATA
1408 // if failed to read/compress:
1410 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1411 static void VM_SV_WritePicture (void)
1413 const char *imgname;
1417 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1419 imgname = PRVM_G_STRING(OFS_PARM1);
1420 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1424 MSG_WriteString(WriteDest(), imgname);
1425 if(Image_Compress(imgname, size, &buf, &size))
1428 MSG_WriteShort(WriteDest(), size);
1429 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1434 MSG_WriteShort(WriteDest(), 0);
1438 //////////////////////////////////////////////////////////
1440 static void VM_SV_makestatic (void)
1445 // allow 0 parameters due to an id1 qc bug in which this function is used
1446 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1447 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1449 if (prog->argc >= 1)
1450 ent = PRVM_G_EDICT(OFS_PARM0);
1452 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1453 if (ent == prog->edicts)
1455 VM_Warning("makestatic: can not modify world entity\n");
1458 if (ent->priv.server->free)
1460 VM_Warning("makestatic: can not modify free entity\n");
1465 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1470 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1471 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1472 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1474 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1476 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1477 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1478 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1482 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1483 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1484 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1487 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1488 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1489 for (i=0 ; i<3 ; i++)
1491 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1492 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1495 // throw the entity away now
1499 //=============================================================================
1506 static void VM_SV_setspawnparms (void)
1512 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1514 ent = PRVM_G_EDICT(OFS_PARM0);
1515 i = PRVM_NUM_FOR_EDICT(ent);
1516 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1518 Con_Print("tried to setspawnparms on a non-client\n");
1522 // copy spawn parms out of the client_t
1523 client = svs.clients + i-1;
1524 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1525 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1532 Returns a color vector indicating the lighting at the requested point.
1534 (Internal Operation note: actually measures the light beneath the point, just like
1535 the model lighting on the client)
1540 static void VM_SV_getlight (void)
1542 vec3_t ambientcolor, diffusecolor, diffusenormal;
1544 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1545 p = PRVM_G_VECTOR(OFS_PARM0);
1546 VectorClear(ambientcolor);
1547 VectorClear(diffusecolor);
1548 VectorClear(diffusenormal);
1549 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1550 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1551 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1556 unsigned char type; // 1/2/8 or other value if isn't used
1560 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1561 static int vm_customstats_last;
1563 void VM_CustomStats_Clear (void)
1567 Z_Free(vm_customstats);
1568 vm_customstats = NULL;
1569 vm_customstats_last = -1;
1573 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1581 for(i=0; i<vm_customstats_last+1 ;i++)
1583 if(!vm_customstats[i].type)
1585 switch(vm_customstats[i].type)
1587 //string as 16 bytes
1590 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1591 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1592 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1593 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1594 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1596 //float field sent as-is
1598 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1600 //integer value of float field
1602 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1610 // void(float index, float type, .void field) SV_AddStat = #232;
1611 // Set up an auto-sent player stat.
1612 // Client's get thier own fields sent to them. Index may not be less than 32.
1613 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1614 // 1: string (4 stats carrying a total of 16 charactures)
1615 // 2: float (one stat, float converted to an integer for transportation)
1616 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1617 static void VM_SV_AddStat (void)
1622 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1626 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1629 VM_Warning("PF_SV_AddStat: not enough memory\n");
1633 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1634 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1635 off = PRVM_G_INT (OFS_PARM2);
1640 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1643 if(i >= (MAX_CL_STATS-32))
1645 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1648 if(i > (MAX_CL_STATS-32-4) && type == 1)
1650 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1653 vm_customstats[i].type = type;
1654 vm_customstats[i].fieldoffset = off;
1655 if(vm_customstats_last < i)
1656 vm_customstats_last = i;
1663 copies data from one entity to another
1665 copyentity(src, dst)
1668 static void VM_SV_copyentity (void)
1670 prvm_edict_t *in, *out;
1671 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1672 in = PRVM_G_EDICT(OFS_PARM0);
1673 if (in == prog->edicts)
1675 VM_Warning("copyentity: can not read world entity\n");
1678 if (in->priv.server->free)
1680 VM_Warning("copyentity: can not read free entity\n");
1683 out = PRVM_G_EDICT(OFS_PARM1);
1684 if (out == prog->edicts)
1686 VM_Warning("copyentity: can not modify world entity\n");
1689 if (out->priv.server->free)
1691 VM_Warning("copyentity: can not modify free entity\n");
1694 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1703 sets the color of a client and broadcasts the update to all connected clients
1705 setcolor(clientent, value)
1708 static void VM_SV_setcolor (void)
1714 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1715 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1716 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1718 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1720 Con_Print("tried to setcolor a non-client\n");
1724 client = svs.clients + entnum-1;
1727 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1729 client->edict->fields.server->team = (i & 15) + 1;
1732 if (client->old_colors != client->colors)
1734 client->old_colors = client->colors;
1735 // send notification to all clients
1736 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1737 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1738 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1746 effect(origin, modelname, startframe, framecount, framerate)
1749 static void VM_SV_effect (void)
1753 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1754 s = PRVM_G_STRING(OFS_PARM1);
1757 VM_Warning("effect: no model specified\n");
1761 i = SV_ModelIndex(s, 1);
1764 VM_Warning("effect: model not precached\n");
1768 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1770 VM_Warning("effect: framecount < 1\n");
1774 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1776 VM_Warning("effect: framerate < 1\n");
1780 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));
1783 static void VM_SV_te_blood (void)
1785 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1786 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1788 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1789 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1791 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1792 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1793 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1795 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1796 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1797 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1799 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1800 SV_FlushBroadcastMessages();
1803 static void VM_SV_te_bloodshower (void)
1805 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1806 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1808 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1809 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1811 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1812 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1813 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1815 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1816 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1817 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1819 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1821 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1822 SV_FlushBroadcastMessages();
1825 static void VM_SV_te_explosionrgb (void)
1827 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1828 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1829 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1831 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1832 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1833 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1835 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1836 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1837 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1838 SV_FlushBroadcastMessages();
1841 static void VM_SV_te_particlecube (void)
1843 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1844 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1846 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1847 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1849 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1850 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1851 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1853 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1854 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1855 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1857 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1858 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1859 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1861 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1863 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1864 // gravity true/false
1865 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1867 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1868 SV_FlushBroadcastMessages();
1871 static void VM_SV_te_particlerain (void)
1873 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1874 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1876 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1877 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1879 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1880 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1881 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1885 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1887 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1888 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1889 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1891 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1893 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1894 SV_FlushBroadcastMessages();
1897 static void VM_SV_te_particlesnow (void)
1899 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1900 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1902 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1903 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1905 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1906 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1909 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1913 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1914 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1915 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1917 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1919 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1920 SV_FlushBroadcastMessages();
1923 static void VM_SV_te_spark (void)
1925 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1926 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1928 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1929 MSG_WriteByte(&sv.datagram, TE_SPARK);
1931 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1932 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1933 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1935 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1936 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1937 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1939 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1940 SV_FlushBroadcastMessages();
1943 static void VM_SV_te_gunshotquad (void)
1945 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1946 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1947 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1949 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1950 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1951 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1952 SV_FlushBroadcastMessages();
1955 static void VM_SV_te_spikequad (void)
1957 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
1958 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1959 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1961 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1962 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1963 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1964 SV_FlushBroadcastMessages();
1967 static void VM_SV_te_superspikequad (void)
1969 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
1970 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1971 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1973 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1974 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1976 SV_FlushBroadcastMessages();
1979 static void VM_SV_te_explosionquad (void)
1981 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
1982 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1983 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1985 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1986 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1987 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1988 SV_FlushBroadcastMessages();
1991 static void VM_SV_te_smallflash (void)
1993 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
1994 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1995 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1997 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1998 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1999 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2000 SV_FlushBroadcastMessages();
2003 static void VM_SV_te_customflash (void)
2005 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2006 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2008 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2009 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2011 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2012 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2013 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2015 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2017 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2019 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2020 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2021 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2022 SV_FlushBroadcastMessages();
2025 static void VM_SV_te_gunshot (void)
2027 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2028 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2029 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2031 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2032 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2033 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2034 SV_FlushBroadcastMessages();
2037 static void VM_SV_te_spike (void)
2039 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2040 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2041 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2043 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2044 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2045 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2046 SV_FlushBroadcastMessages();
2049 static void VM_SV_te_superspike (void)
2051 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2052 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2053 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2055 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2056 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2057 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2058 SV_FlushBroadcastMessages();
2061 static void VM_SV_te_explosion (void)
2063 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2064 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2065 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2067 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2068 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2069 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2070 SV_FlushBroadcastMessages();
2073 static void VM_SV_te_tarexplosion (void)
2075 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2076 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2077 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2079 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2080 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2081 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2082 SV_FlushBroadcastMessages();
2085 static void VM_SV_te_wizspike (void)
2087 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2088 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2089 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2091 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2092 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2093 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2094 SV_FlushBroadcastMessages();
2097 static void VM_SV_te_knightspike (void)
2099 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2100 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2101 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2103 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2104 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2105 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2106 SV_FlushBroadcastMessages();
2109 static void VM_SV_te_lavasplash (void)
2111 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2112 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2113 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2115 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2116 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2117 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2118 SV_FlushBroadcastMessages();
2121 static void VM_SV_te_teleport (void)
2123 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2124 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2125 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2127 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2128 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2129 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2130 SV_FlushBroadcastMessages();
2133 static void VM_SV_te_explosion2 (void)
2135 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2136 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2137 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2139 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2140 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2141 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2143 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2144 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2145 SV_FlushBroadcastMessages();
2148 static void VM_SV_te_lightning1 (void)
2150 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2151 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2152 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2154 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2156 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2157 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2158 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2160 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2161 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2162 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2163 SV_FlushBroadcastMessages();
2166 static void VM_SV_te_lightning2 (void)
2168 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2169 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2170 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2172 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2174 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2175 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2176 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2178 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2179 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2180 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2181 SV_FlushBroadcastMessages();
2184 static void VM_SV_te_lightning3 (void)
2186 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2187 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2188 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2190 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2192 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2193 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2194 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2196 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2197 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2198 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2199 SV_FlushBroadcastMessages();
2202 static void VM_SV_te_beam (void)
2204 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2205 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2206 MSG_WriteByte(&sv.datagram, TE_BEAM);
2208 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2210 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2211 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2212 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2214 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2215 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2216 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2217 SV_FlushBroadcastMessages();
2220 static void VM_SV_te_plasmaburn (void)
2222 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2223 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2224 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2225 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2226 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2227 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2228 SV_FlushBroadcastMessages();
2231 static void VM_SV_te_flamejet (void)
2233 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2234 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2235 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2237 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2238 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2239 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2245 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2246 SV_FlushBroadcastMessages();
2249 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2252 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2254 bestdist = 1000000000;
2256 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2258 // clip original point to each triangle of the surface and find the
2259 // triangle that is closest
2260 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2261 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2262 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2263 TriangleNormal(v[0], v[1], v[2], facenormal);
2264 VectorNormalize(facenormal);
2265 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2266 VectorMA(p, offsetdist, facenormal, temp);
2267 for (j = 0, k = 2;j < 3;k = j, j++)
2269 VectorSubtract(v[k], v[j], edgenormal);
2270 CrossProduct(edgenormal, facenormal, sidenormal);
2271 VectorNormalize(sidenormal);
2272 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2274 VectorMA(temp, offsetdist, sidenormal, temp);
2276 dist = VectorDistance2(temp, p);
2277 if (bestdist > dist)
2280 VectorCopy(temp, out);
2285 #define getmodel SV_GetModelFromEdict
2287 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2289 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2291 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2295 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2296 static void VM_SV_getsurfacenumpoints(void)
2299 msurface_t *surface;
2300 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2301 // return 0 if no such surface
2302 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2304 PRVM_G_FLOAT(OFS_RETURN) = 0;
2308 // note: this (incorrectly) assumes it is a simple polygon
2309 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2311 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2312 static void VM_SV_getsurfacepoint(void)
2316 msurface_t *surface;
2318 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2319 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2320 ed = PRVM_G_EDICT(OFS_PARM0);
2321 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2323 // note: this (incorrectly) assumes it is a simple polygon
2324 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2325 if (pointnum < 0 || pointnum >= surface->num_vertices)
2327 // FIXME: implement rotation/scaling
2328 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2330 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2331 // float SPA_POSITION = 0;
2332 // float SPA_S_AXIS = 1;
2333 // float SPA_T_AXIS = 2;
2334 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2335 // float SPA_TEXCOORDS0 = 4;
2336 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2337 // float SPA_LIGHTMAP0_COLOR = 6;
2338 static void VM_SV_getsurfacepointattribute(void)
2342 msurface_t *surface;
2346 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2347 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2348 ed = PRVM_G_EDICT(OFS_PARM0);
2349 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2351 // note: this (incorrectly) assumes it is a simple polygon
2352 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2353 if (pointnum < 0 || pointnum >= surface->num_vertices)
2355 // FIXME: implement rotation/scaling
2356 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2358 switch( attributetype ) {
2359 // float SPA_POSITION = 0;
2361 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2363 // float SPA_S_AXIS = 1;
2365 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2367 // float SPA_T_AXIS = 2;
2369 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2371 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2373 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2375 // float SPA_TEXCOORDS0 = 4;
2377 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2378 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2379 ret[0] = texcoord[0];
2380 ret[1] = texcoord[1];
2384 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2386 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2387 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2388 ret[0] = texcoord[0];
2389 ret[1] = texcoord[1];
2393 // float SPA_LIGHTMAP0_COLOR = 6;
2395 // ignore alpha for now..
2396 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2399 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2403 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2404 static void VM_SV_getsurfacenormal(void)
2407 msurface_t *surface;
2409 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2410 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2411 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2413 // FIXME: implement rotation/scaling
2414 // note: this (incorrectly) assumes it is a simple polygon
2415 // note: this only returns the first triangle, so it doesn't work very
2416 // well for curved surfaces or arbitrary meshes
2417 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);
2418 VectorNormalize(normal);
2419 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2421 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2422 static void VM_SV_getsurfacetexture(void)
2425 msurface_t *surface;
2426 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2427 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2428 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2430 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2432 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2433 static void VM_SV_getsurfacenearpoint(void)
2435 int surfacenum, best;
2437 vec_t dist, bestdist;
2440 msurface_t *surface;
2442 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2443 PRVM_G_FLOAT(OFS_RETURN) = -1;
2444 ed = PRVM_G_EDICT(OFS_PARM0);
2445 point = PRVM_G_VECTOR(OFS_PARM1);
2447 if (!ed || ed->priv.server->free)
2449 model = getmodel(ed);
2450 if (!model || !model->num_surfaces)
2453 // FIXME: implement rotation/scaling
2454 VectorSubtract(point, ed->fields.server->origin, p);
2456 bestdist = 1000000000;
2457 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2459 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2460 // first see if the nearest point on the surface's box is closer than the previous match
2461 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2462 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2463 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2464 dist = VectorLength2(clipped);
2465 if (dist < bestdist)
2467 // it is, check the nearest point on the actual geometry
2468 clippointtosurface(model, surface, p, clipped);
2469 VectorSubtract(clipped, p, clipped);
2470 dist += VectorLength2(clipped);
2471 if (dist < bestdist)
2473 // that's closer too, store it as the best match
2479 PRVM_G_FLOAT(OFS_RETURN) = best;
2481 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2482 static void VM_SV_getsurfaceclippedpoint(void)
2486 msurface_t *surface;
2488 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2489 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2490 ed = PRVM_G_EDICT(OFS_PARM0);
2491 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2493 // FIXME: implement rotation/scaling
2494 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2495 clippointtosurface(model, surface, p, out);
2496 // FIXME: implement rotation/scaling
2497 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2500 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2501 //this function originally written by KrimZon, made shorter by LordHavoc
2502 static void VM_SV_clientcommand (void)
2504 client_t *temp_client;
2506 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2508 //find client for this entity
2509 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2510 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2512 Con_Print("PF_clientcommand: entity is not a client\n");
2516 temp_client = host_client;
2517 host_client = svs.clients + i;
2518 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2519 host_client = temp_client;
2522 //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)
2523 static void VM_SV_setattachment (void)
2525 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2526 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2527 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2530 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2532 if (e == prog->edicts)
2534 VM_Warning("setattachment: can not modify world entity\n");
2537 if (e->priv.server->free)
2539 VM_Warning("setattachment: can not modify free entity\n");
2543 if (tagentity == NULL)
2544 tagentity = prog->edicts;
2546 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2548 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2550 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2553 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2555 model = SV_GetModelFromEdict(tagentity);
2558 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2560 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);
2563 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));
2567 /////////////////////////////////////////
2568 // DP_MD3_TAGINFO extension coded by VorteX
2570 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2574 i = (int)e->fields.server->modelindex;
2575 if (i < 1 || i >= MAX_MODELS)
2578 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2581 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2588 Matrix4x4_CreateIdentity(tag_localmatrix);
2590 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2592 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2603 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2607 float pitchsign = 1;
2610 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2611 if (val && val->_float != 0)
2612 scale = val->_float;
2615 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);
2618 pitchsign = SV_GetPitchSign(ent);
2619 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);
2623 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2626 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->num_bones)
2628 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2629 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2630 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2631 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2633 *out = identitymatrix;
2637 // Warnings/errors code:
2638 // 0 - normal (everything all-right)
2641 // 3 - null or non-precached model
2642 // 4 - no tags with requested index
2643 // 5 - runaway loop at attachment chain
2644 extern cvar_t cl_bob;
2645 extern cvar_t cl_bobcycle;
2646 extern cvar_t cl_bobup;
2647 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2651 int modelindex, attachloop;
2652 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2655 *out = identitymatrix; // warnings and errors return identical matrix
2657 if (ent == prog->edicts)
2659 if (ent->priv.server->free)
2662 modelindex = (int)ent->fields.server->modelindex;
2663 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2666 model = SV_GetModelByIndex(modelindex);
2668 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2669 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2670 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2672 tagmatrix = identitymatrix;
2673 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2677 if (attachloop >= 256) // prevent runaway looping
2679 // apply transformation by child's tagindex on parent entity and then
2680 // by parent entity itself
2681 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2682 if (ret && attachloop == 0)
2684 SV_GetEntityMatrix(ent, &entitymatrix, false);
2685 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2686 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2687 // next iteration we process the parent entity
2688 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2690 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2691 ent = PRVM_EDICT_NUM(val->edict);
2698 // RENDER_VIEWMODEL magic
2699 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2701 Matrix4x4_Copy(&tagmatrix, out);
2702 ent = PRVM_EDICT_NUM(val->edict);
2704 SV_GetEntityMatrix(ent, &entitymatrix, true);
2705 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2708 // Cl_bob, ported from rendering code
2709 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2712 // LordHavoc: this code is *weird*, but not replacable (I think it
2713 // should be done in QC on the server, but oh well, quake is quake)
2714 // LordHavoc: figured out bobup: the time at which the sin is at 180
2715 // degrees (which allows lengthening or squishing the peak or valley)
2716 cycle = sv.time/cl_bobcycle.value;
2717 cycle -= (int)cycle;
2718 if (cycle < cl_bobup.value)
2719 cycle = sin(M_PI * cycle / cl_bobup.value);
2721 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2722 // bob is proportional to velocity in the xy plane
2723 // (don't count Z, or jumping messes it up)
2724 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;
2725 bob = bob*0.3 + bob*0.7*cycle;
2726 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2733 //float(entity ent, string tagname) gettagindex;
2735 static void VM_SV_gettagindex (void)
2738 const char *tag_name;
2741 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2743 ent = PRVM_G_EDICT(OFS_PARM0);
2744 tag_name = PRVM_G_STRING(OFS_PARM1);
2746 if (ent == prog->edicts)
2748 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2751 if (ent->priv.server->free)
2753 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2758 if (!SV_GetModelFromEdict(ent))
2759 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2762 tag_index = SV_GetTagIndex(ent, tag_name);
2764 if(developer.integer >= 100)
2765 Con_Printf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2767 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2770 //vector(entity ent, float tagindex) gettaginfo;
2771 static void VM_SV_gettaginfo (void)
2775 matrix4x4_t tag_matrix;
2776 matrix4x4_t tag_localmatrix;
2778 const char *tagname;
2781 vec3_t fo, le, up, trans;
2782 const dp_model_t *model;
2784 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2786 e = PRVM_G_EDICT(OFS_PARM0);
2787 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2789 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2790 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2791 VectorScale(le, -1, prog->globals.server->v_right);
2792 model = SV_GetModelFromEdict(e);
2793 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2794 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2795 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2796 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2797 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2799 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2800 val->_float = parentindex;
2801 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2802 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2803 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2804 VectorCopy(trans, val->vector);
2805 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2806 VectorCopy(fo, val->vector);
2807 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2808 VectorScale(le, -1, val->vector);
2809 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2810 VectorCopy(up, val->vector);
2815 VM_Warning("gettagindex: can't affect world entity\n");
2818 VM_Warning("gettagindex: can't affect free entity\n");
2821 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2824 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2827 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2832 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2833 static void VM_SV_dropclient (void)
2836 client_t *oldhostclient;
2837 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2838 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2839 if (clientnum < 0 || clientnum >= svs.maxclients)
2841 VM_Warning("dropclient: not a client\n");
2844 if (!svs.clients[clientnum].active)
2846 VM_Warning("dropclient: that client slot is not connected\n");
2849 oldhostclient = host_client;
2850 host_client = svs.clients + clientnum;
2851 SV_DropClient(false);
2852 host_client = oldhostclient;
2855 //entity() spawnclient (DP_SV_BOTCLIENT)
2856 static void VM_SV_spawnclient (void)
2860 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2861 prog->xfunction->builtinsprofile += 2;
2863 for (i = 0;i < svs.maxclients;i++)
2865 if (!svs.clients[i].active)
2867 prog->xfunction->builtinsprofile += 100;
2868 SV_ConnectClient (i, NULL);
2869 // this has to be set or else ClientDisconnect won't be called
2870 // we assume the qc will call ClientConnect...
2871 svs.clients[i].clientconnectcalled = true;
2872 ed = PRVM_EDICT_NUM(i + 1);
2876 VM_RETURN_EDICT(ed);
2879 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2880 static void VM_SV_clienttype (void)
2883 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2884 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2885 if (clientnum < 0 || clientnum >= svs.maxclients)
2886 PRVM_G_FLOAT(OFS_RETURN) = 3;
2887 else if (!svs.clients[clientnum].active)
2888 PRVM_G_FLOAT(OFS_RETURN) = 0;
2889 else if (svs.clients[clientnum].netconnection)
2890 PRVM_G_FLOAT(OFS_RETURN) = 1;
2892 PRVM_G_FLOAT(OFS_RETURN) = 2;
2899 string(string key) serverkey
2902 void VM_SV_serverkey(void)
2904 char string[VM_STRINGTEMP_LENGTH];
2905 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2906 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2907 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2910 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2911 static void VM_SV_setmodelindex (void)
2916 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2918 e = PRVM_G_EDICT(OFS_PARM0);
2919 if (e == prog->edicts)
2921 VM_Warning("setmodelindex: can not modify world entity\n");
2924 if (e->priv.server->free)
2926 VM_Warning("setmodelindex: can not modify free entity\n");
2929 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2930 if (i <= 0 || i >= MAX_MODELS)
2932 VM_Warning("setmodelindex: invalid modelindex\n");
2935 if (!sv.model_precache[i][0])
2937 VM_Warning("setmodelindex: model not precached\n");
2941 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2942 e->fields.server->modelindex = i;
2944 mod = SV_GetModelByIndex(i);
2948 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2949 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2951 SetMinMaxSize (e, quakemins, quakemaxs, true);
2954 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
2957 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2958 static void VM_SV_modelnameforindex (void)
2961 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2963 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2965 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2966 if (i <= 0 || i >= MAX_MODELS)
2968 VM_Warning("modelnameforindex: invalid modelindex\n");
2971 if (!sv.model_precache[i][0])
2973 VM_Warning("modelnameforindex: model not precached\n");
2977 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
2980 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2981 static void VM_SV_particleeffectnum (void)
2984 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2985 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2988 PRVM_G_FLOAT(OFS_RETURN) = i;
2991 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2992 static void VM_SV_trailparticles (void)
2994 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2996 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
2999 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3000 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3001 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3002 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3003 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3004 SV_FlushBroadcastMessages();
3007 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3008 static void VM_SV_pointparticles (void)
3010 int effectnum, count;
3012 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3014 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3017 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3018 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3019 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3020 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3021 if (count == 1 && !VectorLength2(vel))
3024 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3025 MSG_WriteShort(&sv.datagram, effectnum);
3026 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3030 // 1+2+12+12+2=29 bytes
3031 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3032 MSG_WriteShort(&sv.datagram, effectnum);
3033 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3034 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3035 MSG_WriteShort(&sv.datagram, count);
3038 SV_FlushBroadcastMessages();
3041 //PF_setpause, // void(float pause) setpause = #531;
3042 static void VM_SV_setpause(void) {
3044 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3045 if (pauseValue != 0) { //pause the game
3047 sv.pausedstart = Sys_DoubleTime();
3048 } else { //disable pause, in case it was enabled
3049 if (sv.paused != 0) {
3054 // send notification to all clients
3055 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3056 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3059 // #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.
3060 static void VM_SV_skel_create(void)
3062 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3063 dp_model_t *model = SV_GetModelByIndex(modelindex);
3064 skeleton_t *skeleton;
3066 PRVM_G_FLOAT(OFS_RETURN) = 0;
3067 if (!model || !model->num_bones)
3069 for (i = 0;i < MAX_EDICTS;i++)
3070 if (!prog->skeletons[i])
3072 if (i == MAX_EDICTS)
3074 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3075 skeleton->model = model;
3076 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3077 // initialize to identity matrices
3078 for (i = 0;i < skeleton->model->num_bones;i++)
3079 skeleton->relativetransforms[i] = identitymatrix;
3080 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3083 // #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
3084 static void VM_SV_skel_build(void)
3086 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3087 skeleton_t *skeleton;
3088 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3089 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3090 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3091 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3092 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3093 dp_model_t *model = SV_GetModelByIndex(modelindex);
3098 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3099 frameblend_t frameblend[MAX_FRAMEBLENDS];
3100 matrix4x4_t blendedmatrix;
3102 PRVM_G_FLOAT(OFS_RETURN) = 0;
3103 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3105 firstbone = max(0, firstbone);
3106 lastbone = min(lastbone, model->num_bones - 1);
3107 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3108 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3109 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3110 blendfrac = 1.0f - retainfrac;
3111 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3112 frameblend[numblends].lerp *= blendfrac;
3113 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3115 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3116 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3117 for (blendindex = 0;blendindex < numblends;blendindex++)
3119 Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3120 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3122 skeleton->relativetransforms[bonenum] = blendedmatrix;
3124 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3127 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3128 static void VM_SV_skel_get_numbones(void)
3130 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3131 skeleton_t *skeleton;
3132 PRVM_G_FLOAT(OFS_RETURN) = 0;
3133 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3135 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3138 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3139 static void VM_SV_skel_get_bonename(void)
3141 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3142 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3143 skeleton_t *skeleton;
3144 PRVM_G_INT(OFS_RETURN) = 0;
3145 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3147 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3149 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3152 // #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)
3153 static void VM_SV_skel_get_boneparent(void)
3155 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3156 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3157 skeleton_t *skeleton;
3158 PRVM_G_FLOAT(OFS_RETURN) = 0;
3159 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3161 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3163 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3166 // #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
3167 static void VM_SV_skel_find_bone(void)
3169 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3170 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3171 skeleton_t *skeleton;
3172 PRVM_G_FLOAT(OFS_RETURN) = 0;
3173 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3175 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3178 // #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)
3179 static void VM_SV_skel_get_bonerel(void)
3181 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3182 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3183 skeleton_t *skeleton;
3185 vec3_t forward, left, up, origin;
3186 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3187 VectorClear(prog->globals.client->v_forward);
3188 VectorClear(prog->globals.client->v_right);
3189 VectorClear(prog->globals.client->v_up);
3190 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3192 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3194 matrix = skeleton->relativetransforms[bonenum];
3195 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3196 VectorCopy(forward, prog->globals.client->v_forward);
3197 VectorNegate(left, prog->globals.client->v_right);
3198 VectorCopy(up, prog->globals.client->v_up);
3199 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3202 // #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)
3203 static void VM_SV_skel_get_boneabs(void)
3205 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3206 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3207 skeleton_t *skeleton;
3210 vec3_t forward, left, up, origin;
3211 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3212 VectorClear(prog->globals.client->v_forward);
3213 VectorClear(prog->globals.client->v_right);
3214 VectorClear(prog->globals.client->v_up);
3215 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3217 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3219 matrix = skeleton->relativetransforms[bonenum];
3220 // convert to absolute
3221 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3224 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3226 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3227 VectorCopy(forward, prog->globals.client->v_forward);
3228 VectorNegate(left, prog->globals.client->v_right);
3229 VectorCopy(up, prog->globals.client->v_up);
3230 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3233 // #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)
3234 static void VM_SV_skel_set_bone(void)
3236 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3237 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3238 vec3_t forward, left, up, origin;
3239 skeleton_t *skeleton;
3241 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3243 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3245 VectorCopy(prog->globals.client->v_forward, forward);
3246 VectorNegate(prog->globals.client->v_right, left);
3247 VectorCopy(prog->globals.client->v_up, up);
3248 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3249 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3250 skeleton->relativetransforms[bonenum] = matrix;
3253 // #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)
3254 static void VM_SV_skel_mul_bone(void)
3256 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3257 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3258 vec3_t forward, left, up, origin;
3259 skeleton_t *skeleton;
3262 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3264 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3266 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3267 VectorCopy(prog->globals.client->v_forward, forward);
3268 VectorNegate(prog->globals.client->v_right, left);
3269 VectorCopy(prog->globals.client->v_up, up);
3270 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3271 temp = skeleton->relativetransforms[bonenum];
3272 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3275 // #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)
3276 static void VM_SV_skel_mul_bones(void)
3278 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3279 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3280 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3282 vec3_t forward, left, up, origin;
3283 skeleton_t *skeleton;
3286 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3288 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3289 VectorCopy(prog->globals.client->v_forward, forward);
3290 VectorNegate(prog->globals.client->v_right, left);
3291 VectorCopy(prog->globals.client->v_up, up);
3292 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3293 firstbone = max(0, firstbone);
3294 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3295 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3297 temp = skeleton->relativetransforms[bonenum];
3298 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3302 // #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
3303 static void VM_SV_skel_copybones(void)
3305 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3306 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3307 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3308 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3310 skeleton_t *skeletondst;
3311 skeleton_t *skeletonsrc;
3312 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3314 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3316 firstbone = max(0, firstbone);
3317 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3318 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3319 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3320 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3323 // #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)
3324 static void VM_SV_skel_delete(void)
3326 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3327 skeleton_t *skeleton;
3328 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3331 prog->skeletons[skeletonindex] = NULL;
3334 // #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
3335 static void VM_SV_frameforname(void)
3337 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3338 dp_model_t *model = SV_GetModelByIndex(modelindex);
3339 const char *name = PRVM_G_STRING(OFS_PARM1);
3341 PRVM_G_FLOAT(OFS_RETURN) = -1;
3342 if (!model || !model->animscenes)
3344 for (i = 0;i < model->numframes;i++)
3346 if (!strcasecmp(model->animscenes[i].name, name))
3348 PRVM_G_FLOAT(OFS_RETURN) = i;
3354 // #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.
3355 static void VM_SV_frameduration(void)
3357 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3358 dp_model_t *model = SV_GetModelByIndex(modelindex);
3359 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3360 PRVM_G_FLOAT(OFS_RETURN) = 0;
3361 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3363 if (model->animscenes[framenum].framerate)
3364 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3368 prvm_builtin_t vm_sv_builtins[] = {
3369 NULL, // #0 NULL function (not callable) (QUAKE)
3370 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3371 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3372 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3373 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3374 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3375 VM_break, // #6 void() break (QUAKE)
3376 VM_random, // #7 float() random (QUAKE)
3377 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3378 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3379 VM_error, // #10 void(string e) error (QUAKE)
3380 VM_objerror, // #11 void(string e) objerror (QUAKE)
3381 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3382 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3383 VM_spawn, // #14 entity() spawn (QUAKE)
3384 VM_remove, // #15 void(entity e) remove (QUAKE)
3385 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3386 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3387 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3388 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3389 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3390 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3391 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3392 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3393 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3394 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3395 VM_ftos, // #26 string(float f) ftos (QUAKE)
3396 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3397 VM_coredump, // #28 void() coredump (QUAKE)
3398 VM_traceon, // #29 void() traceon (QUAKE)
3399 VM_traceoff, // #30 void() traceoff (QUAKE)
3400 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3401 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3402 NULL, // #33 (QUAKE)
3403 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3404 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3405 VM_rint, // #36 float(float v) rint (QUAKE)
3406 VM_floor, // #37 float(float v) floor (QUAKE)
3407 VM_ceil, // #38 float(float v) ceil (QUAKE)
3408 NULL, // #39 (QUAKE)
3409 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3410 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3411 NULL, // #42 (QUAKE)
3412 VM_fabs, // #43 float(float f) fabs (QUAKE)
3413 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3414 VM_cvar, // #45 float(string s) cvar (QUAKE)
3415 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3416 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3417 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3418 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3419 NULL, // #50 (QUAKE)
3420 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3421 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3422 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3423 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3424 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3425 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3426 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3427 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3428 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3429 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3430 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3431 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3432 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3433 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3434 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3435 NULL, // #66 (QUAKE)
3436 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3437 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3438 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3439 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3440 NULL, // #71 (QUAKE)
3441 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3442 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3443 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3444 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3445 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3446 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3447 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3448 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3449 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3450 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3451 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3452 NULL, // #83 (QUAKE)
3453 NULL, // #84 (QUAKE)
3454 NULL, // #85 (QUAKE)
3455 NULL, // #86 (QUAKE)
3456 NULL, // #87 (QUAKE)
3457 NULL, // #88 (QUAKE)
3458 NULL, // #89 (QUAKE)
3459 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3460 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3461 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3462 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3463 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3464 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3465 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3466 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3467 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3468 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3469 // FrikaC and Telejano range #100-#199
3480 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3481 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3482 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3483 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3484 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3485 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3486 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3487 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3488 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3489 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3570 // FTEQW range #200-#299
3589 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3592 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3593 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3594 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3595 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3596 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3597 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3598 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3599 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3600 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3601 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3603 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3611 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3634 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.
3635 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
3636 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3637 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3638 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)
3639 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
3640 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)
3641 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)
3642 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)
3643 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)
3644 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)
3645 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
3646 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)
3647 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
3648 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.
3671 // CSQC range #300-#399
3672 NULL, // #300 void() clearscene (EXT_CSQC)
3673 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3674 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3675 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3676 NULL, // #304 void() renderscene (EXT_CSQC)
3677 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3678 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3679 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3680 NULL, // #308 void() R_EndPolygon
3682 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3683 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3687 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3688 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3689 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3690 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3691 NULL, // #319 void(string name) freepic (EXT_CSQC)
3692 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3693 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3694 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3695 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3696 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3697 NULL, // #325 void(void) drawresetcliparea
3702 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3703 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3704 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3705 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3706 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3707 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3708 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3709 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3710 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3711 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3712 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3713 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3714 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3715 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3716 NULL, // #344 vector() getmousepos (EXT_CSQC)
3717 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3718 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3719 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3720 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3721 NULL, // #349 float() isdemo (EXT_CSQC)
3722 VM_isserver, // #350 float() isserver (EXT_CSQC)
3723 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3724 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3725 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3726 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3732 NULL, // #360 float() readbyte (EXT_CSQC)
3733 NULL, // #361 float() readchar (EXT_CSQC)
3734 NULL, // #362 float() readshort (EXT_CSQC)
3735 NULL, // #363 float() readlong (EXT_CSQC)
3736 NULL, // #364 float() readcoord (EXT_CSQC)
3737 NULL, // #365 float() readangle (EXT_CSQC)
3738 NULL, // #366 string() readstring (EXT_CSQC)
3739 NULL, // #367 float() readfloat (EXT_CSQC)
3772 // LordHavoc's range #400-#499
3773 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3774 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3775 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3776 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3777 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3778 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3779 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3780 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3781 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)
3782 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3783 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3784 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3785 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3786 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3787 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3788 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3789 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3790 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3791 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3792 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3793 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3794 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3795 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3796 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3797 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3798 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3799 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3800 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3801 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3802 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3803 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3804 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3805 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3806 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3807 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3808 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3809 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3810 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3811 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3812 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3813 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3814 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3815 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3816 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3817 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3818 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3819 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3820 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3821 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3822 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3823 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3824 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3825 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3826 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3827 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3828 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3829 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3830 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3832 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3833 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3834 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3835 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3836 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3837 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3838 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3839 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3840 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3841 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3842 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3844 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3845 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3846 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3847 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3848 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3849 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3850 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3851 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3852 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3853 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3854 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3855 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3856 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3857 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3858 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3859 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3867 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3868 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3869 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3870 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3871 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3872 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3873 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3874 VM_SV_WritePicture, // #501
3876 VM_whichpack, // #503 string(string) whichpack = #503;
3883 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3884 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3885 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3886 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3887 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3888 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3889 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3890 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3891 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3892 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3902 VM_loadfromdata, // #529
3903 VM_loadfromfile, // #530
3904 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3978 VM_callfunction, // #605
3979 VM_writetofile, // #606
3980 VM_isfunction, // #607
3986 VM_parseentitydata, // #613
3997 VM_SV_getextresponse, // #624 string getextresponse(void)
4001 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4003 void VM_SV_Cmd_Init(void)
4008 void VM_SV_Cmd_Reset(void)
4010 World_End(&sv.world);
4011 if(prog->funcoffsets.SV_Shutdown)
4013 func_t s = prog->funcoffsets.SV_Shutdown;
4014 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4015 PRVM_ExecuteProgram(s,"SV_Shutdown() required");