6 //============================================================================
11 char *vm_sv_extensions =
16 "DP_CON_ALIASPARAMETERS "
22 "DP_CSQC_ENTITYNOCULL "
23 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
24 "DP_CSQC_MULTIFRAME_INTERPOLATION "
25 "DP_CSQC_SPAWNPARTICLE "
37 "DP_EF_RESTARTANIM_BIT "
42 "DP_ENT_CUSTOMCOLORMAP "
43 "DP_ENT_EXTERIORMODELTOCLIENT "
46 "DP_ENT_LOWPRECISION "
50 "DP_GFX_EXTERNALTEXTURES "
51 "DP_GFX_EXTERNALTEXTURES_PERMAP "
53 "DP_GFX_MODEL_INTERPOLATION "
54 "DP_GFX_QUAKE3MODELTAGS "
58 "DP_HALFLIFE_MAP_CVAR "
61 "DP_LIGHTSTYLE_STATICVALUE "
65 "DP_MOVETYPEBOUNCEMISSILE "
68 "DP_QC_ASINACOSATANATAN2TAN "
74 "DP_QC_CVAR_DEFSTRING "
75 "DP_QC_CVAR_DESCRIPTION "
82 "DP_QC_EXTRESPONSEPACKET "
84 "DP_QC_FINDCHAINFLAGS "
85 "DP_QC_FINDCHAINFLOAT "
86 "DP_QC_FINDCHAIN_TOFIELD "
92 "DP_QC_GETSURFACEPOINTATTRIBUTE "
94 "DP_QC_GETTAGINFO_BONEPROPERTIES "
96 "DP_QC_GETTIME_CDTRACK "
99 "DP_QC_MULTIPLETEMPSTRINGS "
100 "DP_QC_NUM_FOR_EDICT "
102 "DP_QC_SINCOSSQRTPOW "
105 "DP_QC_STRINGBUFFERS "
106 "DP_QC_STRINGBUFFERS_CVARLIST "
107 "DP_QC_STRINGCOLORFUNCTIONS "
108 "DP_QC_STRING_CASE_FUNCTIONS "
110 "DP_QC_TOKENIZEBYSEPARATOR "
111 "DP_QC_TOKENIZE_CONSOLE "
114 "DP_QC_TRACE_MOVETYPE_HITMODEL "
115 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
116 "DP_QC_UNLIMITEDTEMPSTRINGS "
119 "DP_QC_VECTOANGLES_WITH_ROLL "
120 "DP_QC_VECTORVECTORS "
127 "DP_SKELETONOBJECTS "
128 "DP_SND_DIRECTIONLESSATTNNONE "
136 "DP_SV_BOUNCEFACTOR "
137 "DP_SV_CLIENTCOLORS "
140 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
141 "DP_SV_DRAWONLYTOCLIENT "
144 "DP_SV_ENTITYCONTENTSTRANSITION "
145 "DP_SV_MODELFLAGS_AS_EFFECTS "
146 "DP_SV_MOVETYPESTEP_LANDEVENT "
148 "DP_SV_NODRAWTOCLIENT "
149 "DP_SV_ONENTITYNOSPAWNFUNCTION "
150 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
152 "DP_SV_PING_PACKETLOSS "
153 "DP_SV_PLAYERPHYSICS "
154 "DP_SV_POINTPARTICLES "
156 "DP_SV_PRECACHEANYTIME "
160 "DP_SV_ROTATINGBMODEL "
164 "DP_SV_SPAWNFUNC_PREFIX "
165 "DP_SV_WRITEPICTURE "
166 "DP_SV_WRITEUNTERMINATEDSTRING "
170 "DP_TE_EXPLOSIONRGB "
172 "DP_TE_PARTICLECUBE "
173 "DP_TE_PARTICLERAIN "
174 "DP_TE_PARTICLESNOW "
176 "DP_TE_QUADEFFECTS1 "
179 "DP_TE_STANDARDEFFECTBUILTINS "
180 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
184 "FTE_CSQC_SKELETONOBJECTS "
187 "KRIMZON_SV_PARSECLIENTCOMMAND "
190 "NEXUIZ_PLAYERMODEL "
192 "PRYDON_CLIENTCURSOR "
193 "TENEBRAE_GFX_DLIGHTS "
196 //"EXT_CSQC " // not ready yet
203 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.
205 setorigin (entity, origin)
208 static void VM_SV_setorigin (void)
213 VM_SAFEPARMCOUNT(2, VM_setorigin);
215 e = PRVM_G_EDICT(OFS_PARM0);
216 if (e == prog->edicts)
218 VM_Warning("setorigin: can not modify world entity\n");
221 if (e->priv.server->free)
223 VM_Warning("setorigin: can not modify free entity\n");
226 org = PRVM_G_VECTOR(OFS_PARM1);
227 VectorCopy (org, e->fields.server->origin);
231 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
232 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
236 for (i=0 ; i<3 ; i++)
238 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
240 // set derived values
241 VectorCopy (min, e->fields.server->mins);
242 VectorCopy (max, e->fields.server->maxs);
243 VectorSubtract (max, min, e->fields.server->size);
252 the size box is rotated by the current angle
253 LordHavoc: no it isn't...
255 setsize (entity, minvector, maxvector)
258 static void VM_SV_setsize (void)
263 VM_SAFEPARMCOUNT(3, VM_setsize);
265 e = PRVM_G_EDICT(OFS_PARM0);
266 if (e == prog->edicts)
268 VM_Warning("setsize: can not modify world entity\n");
271 if (e->priv.server->free)
273 VM_Warning("setsize: can not modify free entity\n");
276 min = PRVM_G_VECTOR(OFS_PARM1);
277 max = PRVM_G_VECTOR(OFS_PARM2);
278 SetMinMaxSize (e, min, max, false);
286 setmodel(entity, model)
289 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
290 static void VM_SV_setmodel (void)
296 VM_SAFEPARMCOUNT(2, VM_setmodel);
298 e = PRVM_G_EDICT(OFS_PARM0);
299 if (e == prog->edicts)
301 VM_Warning("setmodel: can not modify world entity\n");
304 if (e->priv.server->free)
306 VM_Warning("setmodel: can not modify free entity\n");
309 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
310 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
311 e->fields.server->modelindex = i;
313 mod = SV_GetModelByIndex(i);
317 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
318 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
320 SetMinMaxSize (e, quakemins, quakemaxs, true);
323 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
330 single print to a specific client
332 sprint(clientent, value)
335 static void VM_SV_sprint (void)
339 char string[VM_STRINGTEMP_LENGTH];
341 VM_VarString(1, string, sizeof(string));
343 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
345 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
346 // LordHavoc: div0 requested that sprintto world operate like print
353 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
355 VM_Warning("tried to centerprint to a non-client\n");
359 client = svs.clients + entnum-1;
360 if (!client->netconnection)
363 MSG_WriteChar(&client->netconnection->message,svc_print);
364 MSG_WriteString(&client->netconnection->message, string);
372 single print to a specific client
374 centerprint(clientent, value)
377 static void VM_SV_centerprint (void)
381 char string[VM_STRINGTEMP_LENGTH];
383 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
385 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
387 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
389 VM_Warning("tried to centerprint to a non-client\n");
393 client = svs.clients + entnum-1;
394 if (!client->netconnection)
397 VM_VarString(1, string, sizeof(string));
398 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
399 MSG_WriteString(&client->netconnection->message, string);
406 particle(origin, color, count)
409 static void VM_SV_particle (void)
415 VM_SAFEPARMCOUNT(4, VM_SV_particle);
417 org = PRVM_G_VECTOR(OFS_PARM0);
418 dir = PRVM_G_VECTOR(OFS_PARM1);
419 color = PRVM_G_FLOAT(OFS_PARM2);
420 count = PRVM_G_FLOAT(OFS_PARM3);
421 SV_StartParticle (org, dir, (int)color, (int)count);
431 static void VM_SV_ambientsound (void)
435 float vol, attenuation;
438 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
440 pos = PRVM_G_VECTOR (OFS_PARM0);
441 samp = PRVM_G_STRING(OFS_PARM1);
442 vol = PRVM_G_FLOAT(OFS_PARM2);
443 attenuation = PRVM_G_FLOAT(OFS_PARM3);
445 // check to see if samp was properly precached
446 soundnum = SV_SoundIndex(samp, 1);
454 // add an svc_spawnambient command to the level signon packet
457 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
459 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
461 MSG_WriteVector(&sv.signon, pos, sv.protocol);
463 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
464 MSG_WriteShort (&sv.signon, soundnum);
466 MSG_WriteByte (&sv.signon, soundnum);
468 MSG_WriteByte (&sv.signon, (int)(vol*255));
469 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
477 Each entity can have eight independant sound sources, like voice,
480 Channel 0 is an auto-allocate channel, the others override anything
481 already running on that entity/channel pair.
483 An attenuation of 0 will play full volume everywhere in the level.
484 Larger attenuations will drop off.
488 static void VM_SV_sound (void)
492 prvm_edict_t *entity;
496 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
498 entity = PRVM_G_EDICT(OFS_PARM0);
499 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
500 sample = PRVM_G_STRING(OFS_PARM2);
501 volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
502 attenuation = PRVM_G_FLOAT(OFS_PARM4);
505 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
509 if (volume < 0 || volume > 255)
511 VM_Warning("SV_StartSound: volume must be in range 0-1\n");
515 if (attenuation < 0 || attenuation > 4)
517 VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
521 if (channel < 0 || channel > 7)
523 VM_Warning("SV_StartSound: channel must be in range 0-7\n");
527 SV_StartSound (entity, channel, sample, volume, attenuation);
534 Follows the same logic as VM_SV_sound, except instead of
535 an entity, an origin for the sound is provided, and channel
536 is omitted (since no entity is being tracked).
540 static void VM_SV_pointsound(void)
547 VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
549 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
550 sample = PRVM_G_STRING(OFS_PARM1);
551 volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
552 attenuation = PRVM_G_FLOAT(OFS_PARM3);
554 if (volume < 0 || volume > 255)
556 VM_Warning("SV_StartPointSound: volume must be in range 0-1\n");
560 if (attenuation < 0 || attenuation > 4)
562 VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
566 SV_StartPointSound (org, sample, volume, attenuation);
573 Used for use tracing and shot targeting
574 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
575 if the tryents flag is set.
577 traceline (vector1, vector2, movetype, ignore)
580 static void VM_SV_traceline (void)
587 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
589 prog->xfunction->builtinsprofile += 30;
591 v1 = PRVM_G_VECTOR(OFS_PARM0);
592 v2 = PRVM_G_VECTOR(OFS_PARM1);
593 move = (int)PRVM_G_FLOAT(OFS_PARM2);
594 ent = PRVM_G_EDICT(OFS_PARM3);
596 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]))
597 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));
599 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
601 VM_SetTraceGlobals(&trace);
609 Used for use tracing and shot targeting
610 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
611 if the tryents flag is set.
613 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
616 // LordHavoc: added this for my own use, VERY useful, similar to traceline
617 static void VM_SV_tracebox (void)
619 float *v1, *v2, *m1, *m2;
624 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
626 prog->xfunction->builtinsprofile += 30;
628 v1 = PRVM_G_VECTOR(OFS_PARM0);
629 m1 = PRVM_G_VECTOR(OFS_PARM1);
630 m2 = PRVM_G_VECTOR(OFS_PARM2);
631 v2 = PRVM_G_VECTOR(OFS_PARM3);
632 move = (int)PRVM_G_FLOAT(OFS_PARM4);
633 ent = PRVM_G_EDICT(OFS_PARM5);
635 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]))
636 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));
638 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
640 VM_SetTraceGlobals(&trace);
643 static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
648 vec3_t original_origin;
649 vec3_t original_velocity;
650 vec3_t original_angles;
651 vec3_t original_avelocity;
655 VectorCopy(tossent->fields.server->origin , original_origin );
656 VectorCopy(tossent->fields.server->velocity , original_velocity );
657 VectorCopy(tossent->fields.server->angles , original_angles );
658 VectorCopy(tossent->fields.server->avelocity, original_avelocity);
660 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
661 if (val != NULL && val->_float != 0)
662 gravity = val->_float;
665 gravity *= sv_gravity.value * 0.025;
667 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
669 SV_CheckVelocity (tossent);
670 tossent->fields.server->velocity[2] -= gravity;
671 VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
672 VectorScale (tossent->fields.server->velocity, 0.05, move);
673 VectorAdd (tossent->fields.server->origin, move, end);
674 trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
675 VectorCopy (trace.endpos, tossent->fields.server->origin);
676 tossent->fields.server->velocity[2] -= gravity;
678 if (trace.fraction < 1)
682 VectorCopy(original_origin , tossent->fields.server->origin );
683 VectorCopy(original_velocity , tossent->fields.server->velocity );
684 VectorCopy(original_angles , tossent->fields.server->angles );
685 VectorCopy(original_avelocity, tossent->fields.server->avelocity);
690 static void VM_SV_tracetoss (void)
694 prvm_edict_t *ignore;
696 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
698 prog->xfunction->builtinsprofile += 600;
700 ent = PRVM_G_EDICT(OFS_PARM0);
701 if (ent == prog->edicts)
703 VM_Warning("tracetoss: can not use world entity\n");
706 ignore = PRVM_G_EDICT(OFS_PARM1);
708 trace = SV_Trace_Toss (ent, ignore);
710 VM_SetTraceGlobals(&trace);
713 //============================================================================
715 static int checkpvsbytes;
716 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
718 static int VM_SV_newcheckclient (int check)
724 // cycle to the next one
726 check = bound(1, check, svs.maxclients);
727 if (check == svs.maxclients)
735 prog->xfunction->builtinsprofile++;
737 if (i == svs.maxclients+1)
739 // look up the client's edict
740 ent = PRVM_EDICT_NUM(i);
741 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
742 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
744 // found a valid client (possibly the same one again)
748 // get the PVS for the entity
749 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
751 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
752 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
761 Returns a client (or object that has a client enemy) that would be a
764 If there is more than one valid option, they are cycled each frame
766 If (self.origin + self.viewofs) is not in the PVS of the current target,
767 it is not returned at all.
772 int c_invis, c_notvis;
773 static void VM_SV_checkclient (void)
775 prvm_edict_t *ent, *self;
778 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
780 // find a new check if on a new frame
781 if (sv.time - sv.lastchecktime >= 0.1)
783 sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
784 sv.lastchecktime = sv.time;
787 // return check if it might be visible
788 ent = PRVM_EDICT_NUM(sv.lastcheck);
789 if (ent->priv.server->free || ent->fields.server->health <= 0)
791 VM_RETURN_EDICT(prog->edicts);
795 // if current entity can't possibly see the check entity, return 0
796 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
797 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
798 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
801 VM_RETURN_EDICT(prog->edicts);
805 // might be able to see it
807 VM_RETURN_EDICT(ent);
810 //============================================================================
816 Checks if an entity is in a point's PVS.
817 Should be fast but can be inexact.
819 float checkpvs(vector viewpos, entity viewee) = #240;
822 static void VM_SV_checkpvs (void)
825 prvm_edict_t *viewee;
830 unsigned char fatpvs[MAX_MAP_LEAFS/8];
833 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
834 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
835 viewee = PRVM_G_EDICT(OFS_PARM1);
837 if(viewee->priv.server->free)
839 VM_Warning("checkpvs: can not check free entity\n");
840 PRVM_G_FLOAT(OFS_RETURN) = 4;
845 if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
847 // no PVS support on this worldmodel... darn
848 PRVM_G_FLOAT(OFS_RETURN) = 3;
851 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
854 // viewpos isn't in any PVS... darn
855 PRVM_G_FLOAT(OFS_RETURN) = 2;
858 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
860 // using fat PVS like FTEQW does (slow)
861 if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
863 // no PVS support on this worldmodel... darn
864 PRVM_G_FLOAT(OFS_RETURN) = 3;
867 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
870 // viewpos isn't in any PVS... darn
871 PRVM_G_FLOAT(OFS_RETURN) = 2;
874 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
883 Sends text over to the client's execution buffer
885 stuffcmd (clientent, value, ...)
888 static void VM_SV_stuffcmd (void)
892 char string[VM_STRINGTEMP_LENGTH];
894 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
896 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
897 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
899 VM_Warning("Can't stuffcmd to a non-client\n");
903 VM_VarString(1, string, sizeof(string));
906 host_client = svs.clients + entnum-1;
907 Host_ClientCommands ("%s", string);
915 Returns a chain of entities that have origins within a spherical area
917 findradius (origin, radius)
920 static void VM_SV_findradius (void)
922 prvm_edict_t *ent, *chain;
923 vec_t radius, radius2;
924 vec3_t org, eorg, mins, maxs;
927 static prvm_edict_t *touchedicts[MAX_EDICTS];
930 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
933 chainfield = PRVM_G_INT(OFS_PARM2);
935 chainfield = prog->fieldoffsets.chain;
937 PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
939 chain = (prvm_edict_t *)prog->edicts;
941 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
942 radius = PRVM_G_FLOAT(OFS_PARM1);
943 radius2 = radius * radius;
945 mins[0] = org[0] - (radius + 1);
946 mins[1] = org[1] - (radius + 1);
947 mins[2] = org[2] - (radius + 1);
948 maxs[0] = org[0] + (radius + 1);
949 maxs[1] = org[1] + (radius + 1);
950 maxs[2] = org[2] + (radius + 1);
951 numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
952 if (numtouchedicts > MAX_EDICTS)
954 // this never happens
955 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
956 numtouchedicts = MAX_EDICTS;
958 for (i = 0;i < numtouchedicts;i++)
960 ent = touchedicts[i];
961 prog->xfunction->builtinsprofile++;
962 // Quake did not return non-solid entities but darkplaces does
963 // (note: this is the reason you can't blow up fallen zombies)
964 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
966 // LordHavoc: compare against bounding box rather than center so it
967 // doesn't miss large objects, and use DotProduct instead of Length
968 // for a major speedup
969 VectorSubtract(org, ent->fields.server->origin, eorg);
970 if (sv_gameplayfix_findradiusdistancetobox.integer)
972 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
973 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
974 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
977 VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
978 if (DotProduct(eorg, eorg) < radius2)
980 PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
985 VM_RETURN_EDICT(chain);
988 static void VM_SV_precache_sound (void)
990 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
991 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
994 static void VM_SV_precache_model (void)
996 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
997 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
998 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1005 float(float yaw, float dist[, settrace]) walkmove
1008 static void VM_SV_walkmove (void)
1017 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1019 // assume failure if it returns early
1020 PRVM_G_FLOAT(OFS_RETURN) = 0;
1022 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1023 if (ent == prog->edicts)
1025 VM_Warning("walkmove: can not modify world entity\n");
1028 if (ent->priv.server->free)
1030 VM_Warning("walkmove: can not modify free entity\n");
1033 yaw = PRVM_G_FLOAT(OFS_PARM0);
1034 dist = PRVM_G_FLOAT(OFS_PARM1);
1035 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1037 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1040 yaw = yaw*M_PI*2 / 360;
1042 move[0] = cos(yaw)*dist;
1043 move[1] = sin(yaw)*dist;
1046 // save program state, because SV_movestep may call other progs
1047 oldf = prog->xfunction;
1048 oldself = prog->globals.server->self;
1050 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1053 // restore program state
1054 prog->xfunction = oldf;
1055 prog->globals.server->self = oldself;
1065 static void VM_SV_droptofloor (void)
1071 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1073 // assume failure if it returns early
1074 PRVM_G_FLOAT(OFS_RETURN) = 0;
1076 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1077 if (ent == prog->edicts)
1079 VM_Warning("droptofloor: can not modify world entity\n");
1082 if (ent->priv.server->free)
1084 VM_Warning("droptofloor: can not modify free entity\n");
1088 VectorCopy (ent->fields.server->origin, end);
1091 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1092 SV_UnstickEntity(ent);
1094 trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1095 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1098 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]);
1099 VectorAdd(ent->fields.server->origin, offset, org);
1100 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1101 VectorSubtract(trace.endpos, offset, trace.endpos);
1102 if (trace.startsolid)
1104 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]);
1105 SV_UnstickEntity(ent);
1107 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1108 ent->fields.server->groundentity = 0;
1109 PRVM_G_FLOAT(OFS_RETURN) = 1;
1111 else if (trace.fraction < 1)
1113 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]);
1114 VectorCopy (trace.endpos, ent->fields.server->origin);
1115 SV_UnstickEntity(ent);
1117 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1118 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1119 PRVM_G_FLOAT(OFS_RETURN) = 1;
1120 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1121 ent->priv.server->suspendedinairflag = true;
1126 if (trace.fraction != 1)
1128 if (trace.fraction < 1)
1129 VectorCopy (trace.endpos, ent->fields.server->origin);
1131 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1132 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1133 PRVM_G_FLOAT(OFS_RETURN) = 1;
1134 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1135 ent->priv.server->suspendedinairflag = true;
1144 void(float style, string value) lightstyle
1147 static void VM_SV_lightstyle (void)
1154 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1156 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1157 val = PRVM_G_STRING(OFS_PARM1);
1159 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1160 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
1163 // change the string in sv
1164 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1166 // send message to all clients on this server
1167 if (sv.state != ss_active)
1170 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1172 if (client->active && client->netconnection)
1174 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1175 MSG_WriteChar (&client->netconnection->message,style);
1176 MSG_WriteString (&client->netconnection->message, val);
1186 static void VM_SV_checkbottom (void)
1188 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1189 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1197 static void VM_SV_pointcontents (void)
1199 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1200 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1207 Pick a vector for the player to shoot along
1208 vector aim(entity, missilespeed)
1211 static void VM_SV_aim (void)
1213 prvm_edict_t *ent, *check, *bestent;
1214 vec3_t start, dir, end, bestdir;
1217 float dist, bestdist;
1220 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1222 // assume failure if it returns early
1223 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1224 // if sv_aim is so high it can't possibly accept anything, skip out early
1225 if (sv_aim.value >= 1)
1228 ent = PRVM_G_EDICT(OFS_PARM0);
1229 if (ent == prog->edicts)
1231 VM_Warning("aim: can not use world entity\n");
1234 if (ent->priv.server->free)
1236 VM_Warning("aim: can not use free entity\n");
1239 speed = PRVM_G_FLOAT(OFS_PARM1);
1241 VectorCopy (ent->fields.server->origin, start);
1244 // try sending a trace straight
1245 VectorCopy (prog->globals.server->v_forward, dir);
1246 VectorMA (start, 2048, dir, end);
1247 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1248 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1249 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1251 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1256 // try all possible entities
1257 VectorCopy (dir, bestdir);
1258 bestdist = sv_aim.value;
1261 check = PRVM_NEXT_EDICT(prog->edicts);
1262 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1264 prog->xfunction->builtinsprofile++;
1265 if (check->fields.server->takedamage != DAMAGE_AIM)
1269 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1270 continue; // don't aim at teammate
1271 for (j=0 ; j<3 ; j++)
1272 end[j] = check->fields.server->origin[j]
1273 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1274 VectorSubtract (end, start, dir);
1275 VectorNormalize (dir);
1276 dist = DotProduct (dir, prog->globals.server->v_forward);
1277 if (dist < bestdist)
1278 continue; // to far to turn
1279 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1280 if (tr.ent == check)
1281 { // can shoot at this one
1289 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1290 dist = DotProduct (dir, prog->globals.server->v_forward);
1291 VectorScale (prog->globals.server->v_forward, dist, end);
1293 VectorNormalize (end);
1294 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1298 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1303 ===============================================================================
1307 ===============================================================================
1310 #define MSG_BROADCAST 0 // unreliable to all
1311 #define MSG_ONE 1 // reliable to one (msg_entity)
1312 #define MSG_ALL 2 // reliable to all
1313 #define MSG_INIT 3 // write to the init string
1314 #define MSG_ENTITY 5
1316 sizebuf_t *WriteDest (void)
1322 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1326 return &sv.datagram;
1329 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1330 entnum = PRVM_NUM_FOR_EDICT(ent);
1331 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1333 VM_Warning ("WriteDest: tried to write to non-client\n");
1334 return &sv.reliable_datagram;
1337 return &svs.clients[entnum-1].netconnection->message;
1340 VM_Warning ("WriteDest: bad destination\n");
1342 return &sv.reliable_datagram;
1348 return sv.writeentitiestoclient_msg;
1354 static void VM_SV_WriteByte (void)
1356 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1357 MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1360 static void VM_SV_WriteChar (void)
1362 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1363 MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1366 static void VM_SV_WriteShort (void)
1368 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1369 MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1372 static void VM_SV_WriteLong (void)
1374 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1375 MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1378 static void VM_SV_WriteAngle (void)
1380 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1381 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1384 static void VM_SV_WriteCoord (void)
1386 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1387 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1390 static void VM_SV_WriteString (void)
1392 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1393 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1396 static void VM_SV_WriteUnterminatedString (void)
1398 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1399 MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1403 static void VM_SV_WriteEntity (void)
1405 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1406 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1409 // writes a picture as at most size bytes of data
1411 // IMGNAME \0 SIZE(short) IMGDATA
1412 // if failed to read/compress:
1414 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1415 static void VM_SV_WritePicture (void)
1417 const char *imgname;
1421 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1423 imgname = PRVM_G_STRING(OFS_PARM1);
1424 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1428 MSG_WriteString(WriteDest(), imgname);
1429 if(Image_Compress(imgname, size, &buf, &size))
1432 MSG_WriteShort(WriteDest(), size);
1433 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1438 MSG_WriteShort(WriteDest(), 0);
1442 //////////////////////////////////////////////////////////
1444 static void VM_SV_makestatic (void)
1449 // allow 0 parameters due to an id1 qc bug in which this function is used
1450 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1451 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1453 if (prog->argc >= 1)
1454 ent = PRVM_G_EDICT(OFS_PARM0);
1456 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1457 if (ent == prog->edicts)
1459 VM_Warning("makestatic: can not modify world entity\n");
1462 if (ent->priv.server->free)
1464 VM_Warning("makestatic: can not modify free entity\n");
1469 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1474 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1475 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1476 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1478 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1480 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1481 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1482 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1486 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1487 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1488 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1491 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1492 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1493 for (i=0 ; i<3 ; i++)
1495 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1496 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1499 // throw the entity away now
1503 //=============================================================================
1510 static void VM_SV_setspawnparms (void)
1516 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1518 ent = PRVM_G_EDICT(OFS_PARM0);
1519 i = PRVM_NUM_FOR_EDICT(ent);
1520 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1522 Con_Print("tried to setspawnparms on a non-client\n");
1526 // copy spawn parms out of the client_t
1527 client = svs.clients + i-1;
1528 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1529 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1536 Returns a color vector indicating the lighting at the requested point.
1538 (Internal Operation note: actually measures the light beneath the point, just like
1539 the model lighting on the client)
1544 static void VM_SV_getlight (void)
1546 vec3_t ambientcolor, diffusecolor, diffusenormal;
1548 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1549 p = PRVM_G_VECTOR(OFS_PARM0);
1550 VectorClear(ambientcolor);
1551 VectorClear(diffusecolor);
1552 VectorClear(diffusenormal);
1553 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1554 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1555 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1560 unsigned char type; // 1/2/8 or other value if isn't used
1564 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1565 static int vm_customstats_last;
1567 void VM_CustomStats_Clear (void)
1571 Z_Free(vm_customstats);
1572 vm_customstats = NULL;
1573 vm_customstats_last = -1;
1577 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1585 for(i=0; i<vm_customstats_last+1 ;i++)
1587 if(!vm_customstats[i].type)
1589 switch(vm_customstats[i].type)
1591 //string as 16 bytes
1594 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1595 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1596 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1597 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1598 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1600 //float field sent as-is
1602 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1604 //integer value of float field
1606 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1614 // void(float index, float type, .void field) SV_AddStat = #232;
1615 // Set up an auto-sent player stat.
1616 // Client's get thier own fields sent to them. Index may not be less than 32.
1617 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1618 // 1: string (4 stats carrying a total of 16 charactures)
1619 // 2: float (one stat, float converted to an integer for transportation)
1620 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1621 static void VM_SV_AddStat (void)
1626 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1630 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1633 VM_Warning("PF_SV_AddStat: not enough memory\n");
1637 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1638 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1639 off = PRVM_G_INT (OFS_PARM2);
1644 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1647 if(i >= (MAX_CL_STATS-32))
1649 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1652 if(i > (MAX_CL_STATS-32-4) && type == 1)
1654 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1657 vm_customstats[i].type = type;
1658 vm_customstats[i].fieldoffset = off;
1659 if(vm_customstats_last < i)
1660 vm_customstats_last = i;
1667 copies data from one entity to another
1669 copyentity(src, dst)
1672 static void VM_SV_copyentity (void)
1674 prvm_edict_t *in, *out;
1675 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1676 in = PRVM_G_EDICT(OFS_PARM0);
1677 if (in == prog->edicts)
1679 VM_Warning("copyentity: can not read world entity\n");
1682 if (in->priv.server->free)
1684 VM_Warning("copyentity: can not read free entity\n");
1687 out = PRVM_G_EDICT(OFS_PARM1);
1688 if (out == prog->edicts)
1690 VM_Warning("copyentity: can not modify world entity\n");
1693 if (out->priv.server->free)
1695 VM_Warning("copyentity: can not modify free entity\n");
1698 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1707 sets the color of a client and broadcasts the update to all connected clients
1709 setcolor(clientent, value)
1712 static void VM_SV_setcolor (void)
1718 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1719 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1720 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1722 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1724 Con_Print("tried to setcolor a non-client\n");
1728 client = svs.clients + entnum-1;
1731 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1733 client->edict->fields.server->team = (i & 15) + 1;
1736 if (client->old_colors != client->colors)
1738 client->old_colors = client->colors;
1739 // send notification to all clients
1740 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1741 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1742 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1750 effect(origin, modelname, startframe, framecount, framerate)
1753 static void VM_SV_effect (void)
1757 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1758 s = PRVM_G_STRING(OFS_PARM1);
1761 VM_Warning("effect: no model specified\n");
1765 i = SV_ModelIndex(s, 1);
1768 VM_Warning("effect: model not precached\n");
1772 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1774 VM_Warning("effect: framecount < 1\n");
1778 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1780 VM_Warning("effect: framerate < 1\n");
1784 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));
1787 static void VM_SV_te_blood (void)
1789 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1790 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1792 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1793 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1795 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1796 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1797 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1799 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1800 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1801 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1803 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1804 SV_FlushBroadcastMessages();
1807 static void VM_SV_te_bloodshower (void)
1809 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1810 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1812 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1813 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1815 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1816 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1817 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1819 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1820 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1821 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1823 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1825 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1826 SV_FlushBroadcastMessages();
1829 static void VM_SV_te_explosionrgb (void)
1831 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1832 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1833 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1835 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1836 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1837 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1839 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1840 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1841 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1842 SV_FlushBroadcastMessages();
1845 static void VM_SV_te_particlecube (void)
1847 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1848 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1850 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1851 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1853 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1854 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1855 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1857 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1858 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1859 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1861 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1862 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1863 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1865 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1867 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1868 // gravity true/false
1869 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1871 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1872 SV_FlushBroadcastMessages();
1875 static void VM_SV_te_particlerain (void)
1877 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1878 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1880 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1881 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1885 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1887 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1888 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1889 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1891 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1892 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1893 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1895 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1897 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1898 SV_FlushBroadcastMessages();
1901 static void VM_SV_te_particlesnow (void)
1903 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1904 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1906 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1907 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1909 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1913 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1914 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1915 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1917 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1918 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1919 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1921 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1923 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1924 SV_FlushBroadcastMessages();
1927 static void VM_SV_te_spark (void)
1929 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1930 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1932 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1933 MSG_WriteByte(&sv.datagram, TE_SPARK);
1935 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1936 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1937 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1939 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1940 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1941 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1943 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1944 SV_FlushBroadcastMessages();
1947 static void VM_SV_te_gunshotquad (void)
1949 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1950 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1951 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1953 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1954 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1955 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1956 SV_FlushBroadcastMessages();
1959 static void VM_SV_te_spikequad (void)
1961 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
1962 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1963 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1965 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1966 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1967 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1968 SV_FlushBroadcastMessages();
1971 static void VM_SV_te_superspikequad (void)
1973 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
1974 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1975 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1977 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1978 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1979 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1980 SV_FlushBroadcastMessages();
1983 static void VM_SV_te_explosionquad (void)
1985 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
1986 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1987 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1989 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1990 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1991 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1992 SV_FlushBroadcastMessages();
1995 static void VM_SV_te_smallflash (void)
1997 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
1998 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1999 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2002 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2003 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2004 SV_FlushBroadcastMessages();
2007 static void VM_SV_te_customflash (void)
2009 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2010 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2012 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2013 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2015 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2016 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2017 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2019 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2021 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2023 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2024 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2025 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2026 SV_FlushBroadcastMessages();
2029 static void VM_SV_te_gunshot (void)
2031 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2032 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2033 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2035 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2036 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2037 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2038 SV_FlushBroadcastMessages();
2041 static void VM_SV_te_spike (void)
2043 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2044 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2045 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2047 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2048 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2049 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2050 SV_FlushBroadcastMessages();
2053 static void VM_SV_te_superspike (void)
2055 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2056 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2057 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2059 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2060 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2061 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2062 SV_FlushBroadcastMessages();
2065 static void VM_SV_te_explosion (void)
2067 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2068 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2069 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2071 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2072 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2073 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2074 SV_FlushBroadcastMessages();
2077 static void VM_SV_te_tarexplosion (void)
2079 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2080 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2081 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2083 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2084 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2085 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2086 SV_FlushBroadcastMessages();
2089 static void VM_SV_te_wizspike (void)
2091 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2092 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2093 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2095 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2096 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2097 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2098 SV_FlushBroadcastMessages();
2101 static void VM_SV_te_knightspike (void)
2103 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2104 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2105 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2107 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2108 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2109 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2110 SV_FlushBroadcastMessages();
2113 static void VM_SV_te_lavasplash (void)
2115 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2116 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2117 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2119 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2120 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2121 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2122 SV_FlushBroadcastMessages();
2125 static void VM_SV_te_teleport (void)
2127 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2128 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2129 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2131 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2132 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2133 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2134 SV_FlushBroadcastMessages();
2137 static void VM_SV_te_explosion2 (void)
2139 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2140 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2141 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2143 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2144 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2145 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2147 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2148 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2149 SV_FlushBroadcastMessages();
2152 static void VM_SV_te_lightning1 (void)
2154 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2155 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2156 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2158 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2160 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2161 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2162 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2164 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2165 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2166 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2167 SV_FlushBroadcastMessages();
2170 static void VM_SV_te_lightning2 (void)
2172 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2173 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2174 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2176 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2178 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2179 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2180 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2182 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2185 SV_FlushBroadcastMessages();
2188 static void VM_SV_te_lightning3 (void)
2190 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2191 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2192 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2194 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2196 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2197 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2198 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2200 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2201 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2202 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2203 SV_FlushBroadcastMessages();
2206 static void VM_SV_te_beam (void)
2208 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2209 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2210 MSG_WriteByte(&sv.datagram, TE_BEAM);
2212 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2214 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2215 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2216 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2218 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2221 SV_FlushBroadcastMessages();
2224 static void VM_SV_te_plasmaburn (void)
2226 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2227 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2228 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2229 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2230 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2231 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2232 SV_FlushBroadcastMessages();
2235 static void VM_SV_te_flamejet (void)
2237 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2238 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2239 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2241 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2245 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2246 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2247 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2249 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2250 SV_FlushBroadcastMessages();
2253 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2256 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2258 bestdist = 1000000000;
2260 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2262 // clip original point to each triangle of the surface and find the
2263 // triangle that is closest
2264 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2265 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2266 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2267 TriangleNormal(v[0], v[1], v[2], facenormal);
2268 VectorNormalize(facenormal);
2269 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2270 VectorMA(p, offsetdist, facenormal, temp);
2271 for (j = 0, k = 2;j < 3;k = j, j++)
2273 VectorSubtract(v[k], v[j], edgenormal);
2274 CrossProduct(edgenormal, facenormal, sidenormal);
2275 VectorNormalize(sidenormal);
2276 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2278 VectorMA(temp, offsetdist, sidenormal, temp);
2280 dist = VectorDistance2(temp, p);
2281 if (bestdist > dist)
2284 VectorCopy(temp, out);
2289 #define getmodel SV_GetModelFromEdict
2291 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2293 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2295 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2299 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2300 static void VM_SV_getsurfacenumpoints(void)
2303 msurface_t *surface;
2304 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2305 // return 0 if no such surface
2306 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2308 PRVM_G_FLOAT(OFS_RETURN) = 0;
2312 // note: this (incorrectly) assumes it is a simple polygon
2313 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2315 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2316 static void VM_SV_getsurfacepoint(void)
2320 msurface_t *surface;
2322 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2323 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2324 ed = PRVM_G_EDICT(OFS_PARM0);
2325 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2327 // note: this (incorrectly) assumes it is a simple polygon
2328 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2329 if (pointnum < 0 || pointnum >= surface->num_vertices)
2331 // FIXME: implement rotation/scaling
2332 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2334 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2335 // float SPA_POSITION = 0;
2336 // float SPA_S_AXIS = 1;
2337 // float SPA_T_AXIS = 2;
2338 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2339 // float SPA_TEXCOORDS0 = 4;
2340 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2341 // float SPA_LIGHTMAP0_COLOR = 6;
2342 static void VM_SV_getsurfacepointattribute(void)
2346 msurface_t *surface;
2350 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2351 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2352 ed = PRVM_G_EDICT(OFS_PARM0);
2353 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2355 // note: this (incorrectly) assumes it is a simple polygon
2356 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2357 if (pointnum < 0 || pointnum >= surface->num_vertices)
2359 // FIXME: implement rotation/scaling
2360 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2362 switch( attributetype ) {
2363 // float SPA_POSITION = 0;
2365 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2367 // float SPA_S_AXIS = 1;
2369 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2371 // float SPA_T_AXIS = 2;
2373 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2375 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2377 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2379 // float SPA_TEXCOORDS0 = 4;
2381 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2382 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2383 ret[0] = texcoord[0];
2384 ret[1] = texcoord[1];
2388 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2390 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2391 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2392 ret[0] = texcoord[0];
2393 ret[1] = texcoord[1];
2397 // float SPA_LIGHTMAP0_COLOR = 6;
2399 // ignore alpha for now..
2400 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2403 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2407 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2408 static void VM_SV_getsurfacenormal(void)
2411 msurface_t *surface;
2413 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2414 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2415 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2417 // FIXME: implement rotation/scaling
2418 // note: this (incorrectly) assumes it is a simple polygon
2419 // note: this only returns the first triangle, so it doesn't work very
2420 // well for curved surfaces or arbitrary meshes
2421 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);
2422 VectorNormalize(normal);
2423 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2425 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2426 static void VM_SV_getsurfacetexture(void)
2429 msurface_t *surface;
2430 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2431 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2432 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2434 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2436 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2437 static void VM_SV_getsurfacenearpoint(void)
2439 int surfacenum, best;
2441 vec_t dist, bestdist;
2444 msurface_t *surface;
2446 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2447 PRVM_G_FLOAT(OFS_RETURN) = -1;
2448 ed = PRVM_G_EDICT(OFS_PARM0);
2449 point = PRVM_G_VECTOR(OFS_PARM1);
2451 if (!ed || ed->priv.server->free)
2453 model = getmodel(ed);
2454 if (!model || !model->num_surfaces)
2457 // FIXME: implement rotation/scaling
2458 VectorSubtract(point, ed->fields.server->origin, p);
2460 bestdist = 1000000000;
2461 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2463 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2464 // first see if the nearest point on the surface's box is closer than the previous match
2465 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2466 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2467 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2468 dist = VectorLength2(clipped);
2469 if (dist < bestdist)
2471 // it is, check the nearest point on the actual geometry
2472 clippointtosurface(model, surface, p, clipped);
2473 VectorSubtract(clipped, p, clipped);
2474 dist += VectorLength2(clipped);
2475 if (dist < bestdist)
2477 // that's closer too, store it as the best match
2483 PRVM_G_FLOAT(OFS_RETURN) = best;
2485 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2486 static void VM_SV_getsurfaceclippedpoint(void)
2490 msurface_t *surface;
2492 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2493 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2494 ed = PRVM_G_EDICT(OFS_PARM0);
2495 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2497 // FIXME: implement rotation/scaling
2498 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2499 clippointtosurface(model, surface, p, out);
2500 // FIXME: implement rotation/scaling
2501 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2504 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2505 //this function originally written by KrimZon, made shorter by LordHavoc
2506 static void VM_SV_clientcommand (void)
2508 client_t *temp_client;
2510 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2512 //find client for this entity
2513 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2514 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2516 Con_Print("PF_clientcommand: entity is not a client\n");
2520 temp_client = host_client;
2521 host_client = svs.clients + i;
2522 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2523 host_client = temp_client;
2526 //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)
2527 static void VM_SV_setattachment (void)
2529 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2530 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2531 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2534 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2536 if (e == prog->edicts)
2538 VM_Warning("setattachment: can not modify world entity\n");
2541 if (e->priv.server->free)
2543 VM_Warning("setattachment: can not modify free entity\n");
2547 if (tagentity == NULL)
2548 tagentity = prog->edicts;
2550 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2552 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2554 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2557 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2559 model = SV_GetModelFromEdict(tagentity);
2562 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2564 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);
2567 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));
2571 /////////////////////////////////////////
2572 // DP_MD3_TAGINFO extension coded by VorteX
2574 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2578 i = (int)e->fields.server->modelindex;
2579 if (i < 1 || i >= MAX_MODELS)
2582 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2585 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2592 Matrix4x4_CreateIdentity(tag_localmatrix);
2594 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2596 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2607 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2611 float pitchsign = 1;
2614 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2615 if (val && val->_float != 0)
2616 scale = val->_float;
2619 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);
2622 pitchsign = SV_GetPitchSign(ent);
2623 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);
2627 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2630 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->num_bones)
2632 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2633 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2634 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2635 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2637 *out = identitymatrix;
2641 // Warnings/errors code:
2642 // 0 - normal (everything all-right)
2645 // 3 - null or non-precached model
2646 // 4 - no tags with requested index
2647 // 5 - runaway loop at attachment chain
2648 extern cvar_t cl_bob;
2649 extern cvar_t cl_bobcycle;
2650 extern cvar_t cl_bobup;
2651 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2655 int modelindex, attachloop;
2656 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2659 *out = identitymatrix; // warnings and errors return identical matrix
2661 if (ent == prog->edicts)
2663 if (ent->priv.server->free)
2666 modelindex = (int)ent->fields.server->modelindex;
2667 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2670 model = SV_GetModelByIndex(modelindex);
2672 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2673 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2674 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2676 tagmatrix = identitymatrix;
2677 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2681 if (attachloop >= 256) // prevent runaway looping
2683 // apply transformation by child's tagindex on parent entity and then
2684 // by parent entity itself
2685 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2686 if (ret && attachloop == 0)
2688 SV_GetEntityMatrix(ent, &entitymatrix, false);
2689 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2690 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2691 // next iteration we process the parent entity
2692 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2694 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2695 ent = PRVM_EDICT_NUM(val->edict);
2702 // RENDER_VIEWMODEL magic
2703 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2705 Matrix4x4_Copy(&tagmatrix, out);
2706 ent = PRVM_EDICT_NUM(val->edict);
2708 SV_GetEntityMatrix(ent, &entitymatrix, true);
2709 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2712 // Cl_bob, ported from rendering code
2713 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2716 // LordHavoc: this code is *weird*, but not replacable (I think it
2717 // should be done in QC on the server, but oh well, quake is quake)
2718 // LordHavoc: figured out bobup: the time at which the sin is at 180
2719 // degrees (which allows lengthening or squishing the peak or valley)
2720 cycle = sv.time/cl_bobcycle.value;
2721 cycle -= (int)cycle;
2722 if (cycle < cl_bobup.value)
2723 cycle = sin(M_PI * cycle / cl_bobup.value);
2725 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2726 // bob is proportional to velocity in the xy plane
2727 // (don't count Z, or jumping messes it up)
2728 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;
2729 bob = bob*0.3 + bob*0.7*cycle;
2730 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2737 //float(entity ent, string tagname) gettagindex;
2739 static void VM_SV_gettagindex (void)
2742 const char *tag_name;
2745 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2747 ent = PRVM_G_EDICT(OFS_PARM0);
2748 tag_name = PRVM_G_STRING(OFS_PARM1);
2750 if (ent == prog->edicts)
2752 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2755 if (ent->priv.server->free)
2757 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2762 if (!SV_GetModelFromEdict(ent))
2763 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2766 tag_index = SV_GetTagIndex(ent, tag_name);
2768 if(developer.integer >= 100)
2769 Con_Printf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2771 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2774 //vector(entity ent, float tagindex) gettaginfo;
2775 static void VM_SV_gettaginfo (void)
2779 matrix4x4_t tag_matrix;
2780 matrix4x4_t tag_localmatrix;
2782 const char *tagname;
2785 vec3_t fo, le, up, trans;
2786 const dp_model_t *model;
2788 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2790 e = PRVM_G_EDICT(OFS_PARM0);
2791 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2793 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2794 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2795 VectorScale(le, -1, prog->globals.server->v_right);
2796 model = SV_GetModelFromEdict(e);
2797 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2798 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2799 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2800 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2801 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2803 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2804 val->_float = parentindex;
2805 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2806 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2807 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2808 VectorCopy(trans, val->vector);
2809 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2810 VectorCopy(fo, val->vector);
2811 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2812 VectorScale(le, -1, val->vector);
2813 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2814 VectorCopy(up, val->vector);
2819 VM_Warning("gettagindex: can't affect world entity\n");
2822 VM_Warning("gettagindex: can't affect free entity\n");
2825 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2828 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2831 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2836 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2837 static void VM_SV_dropclient (void)
2840 client_t *oldhostclient;
2841 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2842 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2843 if (clientnum < 0 || clientnum >= svs.maxclients)
2845 VM_Warning("dropclient: not a client\n");
2848 if (!svs.clients[clientnum].active)
2850 VM_Warning("dropclient: that client slot is not connected\n");
2853 oldhostclient = host_client;
2854 host_client = svs.clients + clientnum;
2855 SV_DropClient(false);
2856 host_client = oldhostclient;
2859 //entity() spawnclient (DP_SV_BOTCLIENT)
2860 static void VM_SV_spawnclient (void)
2864 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2865 prog->xfunction->builtinsprofile += 2;
2867 for (i = 0;i < svs.maxclients;i++)
2869 if (!svs.clients[i].active)
2871 prog->xfunction->builtinsprofile += 100;
2872 SV_ConnectClient (i, NULL);
2873 // this has to be set or else ClientDisconnect won't be called
2874 // we assume the qc will call ClientConnect...
2875 svs.clients[i].clientconnectcalled = true;
2876 ed = PRVM_EDICT_NUM(i + 1);
2880 VM_RETURN_EDICT(ed);
2883 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2884 static void VM_SV_clienttype (void)
2887 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2888 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2889 if (clientnum < 0 || clientnum >= svs.maxclients)
2890 PRVM_G_FLOAT(OFS_RETURN) = 3;
2891 else if (!svs.clients[clientnum].active)
2892 PRVM_G_FLOAT(OFS_RETURN) = 0;
2893 else if (svs.clients[clientnum].netconnection)
2894 PRVM_G_FLOAT(OFS_RETURN) = 1;
2896 PRVM_G_FLOAT(OFS_RETURN) = 2;
2903 string(string key) serverkey
2906 void VM_SV_serverkey(void)
2908 char string[VM_STRINGTEMP_LENGTH];
2909 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2910 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2911 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2914 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2915 static void VM_SV_setmodelindex (void)
2920 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2922 e = PRVM_G_EDICT(OFS_PARM0);
2923 if (e == prog->edicts)
2925 VM_Warning("setmodelindex: can not modify world entity\n");
2928 if (e->priv.server->free)
2930 VM_Warning("setmodelindex: can not modify free entity\n");
2933 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2934 if (i <= 0 || i >= MAX_MODELS)
2936 VM_Warning("setmodelindex: invalid modelindex\n");
2939 if (!sv.model_precache[i][0])
2941 VM_Warning("setmodelindex: model not precached\n");
2945 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2946 e->fields.server->modelindex = i;
2948 mod = SV_GetModelByIndex(i);
2952 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2953 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2955 SetMinMaxSize (e, quakemins, quakemaxs, true);
2958 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
2961 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2962 static void VM_SV_modelnameforindex (void)
2965 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2967 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2969 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2970 if (i <= 0 || i >= MAX_MODELS)
2972 VM_Warning("modelnameforindex: invalid modelindex\n");
2975 if (!sv.model_precache[i][0])
2977 VM_Warning("modelnameforindex: model not precached\n");
2981 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
2984 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2985 static void VM_SV_particleeffectnum (void)
2988 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2989 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2992 PRVM_G_FLOAT(OFS_RETURN) = i;
2995 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2996 static void VM_SV_trailparticles (void)
2998 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
3000 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3003 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3004 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3005 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3006 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3007 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3008 SV_FlushBroadcastMessages();
3011 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3012 static void VM_SV_pointparticles (void)
3014 int effectnum, count;
3016 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3018 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3021 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3022 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3023 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3024 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3025 if (count == 1 && !VectorLength2(vel))
3028 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3029 MSG_WriteShort(&sv.datagram, effectnum);
3030 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3034 // 1+2+12+12+2=29 bytes
3035 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3036 MSG_WriteShort(&sv.datagram, effectnum);
3037 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3038 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3039 MSG_WriteShort(&sv.datagram, count);
3042 SV_FlushBroadcastMessages();
3045 //PF_setpause, // void(float pause) setpause = #531;
3046 static void VM_SV_setpause(void) {
3048 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3049 if (pauseValue != 0) { //pause the game
3051 sv.pausedstart = Sys_DoubleTime();
3052 } else { //disable pause, in case it was enabled
3053 if (sv.paused != 0) {
3058 // send notification to all clients
3059 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3060 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3063 // #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.
3064 static void VM_SV_skel_create(void)
3066 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3067 dp_model_t *model = SV_GetModelByIndex(modelindex);
3068 skeleton_t *skeleton;
3070 PRVM_G_FLOAT(OFS_RETURN) = 0;
3071 if (!model || !model->num_bones)
3073 for (i = 0;i < MAX_EDICTS;i++)
3074 if (!prog->skeletons[i])
3076 if (i == MAX_EDICTS)
3078 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3079 skeleton->model = model;
3080 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3081 // initialize to identity matrices
3082 for (i = 0;i < skeleton->model->num_bones;i++)
3083 skeleton->relativetransforms[i] = identitymatrix;
3084 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3087 // #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
3088 static void VM_SV_skel_build(void)
3090 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3091 skeleton_t *skeleton;
3092 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3093 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3094 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3095 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3096 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3097 dp_model_t *model = SV_GetModelByIndex(modelindex);
3102 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3103 frameblend_t frameblend[MAX_FRAMEBLENDS];
3104 matrix4x4_t blendedmatrix;
3106 PRVM_G_FLOAT(OFS_RETURN) = 0;
3107 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3109 firstbone = max(0, firstbone);
3110 lastbone = min(lastbone, model->num_bones - 1);
3111 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3112 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3113 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3114 blendfrac = 1.0f - retainfrac;
3115 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3116 frameblend[numblends].lerp *= blendfrac;
3117 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3119 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3120 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3121 for (blendindex = 0;blendindex < numblends;blendindex++)
3123 Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3124 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3126 skeleton->relativetransforms[bonenum] = blendedmatrix;
3128 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3131 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3132 static void VM_SV_skel_get_numbones(void)
3134 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3135 skeleton_t *skeleton;
3136 PRVM_G_FLOAT(OFS_RETURN) = 0;
3137 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3139 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3142 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3143 static void VM_SV_skel_get_bonename(void)
3145 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3146 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3147 skeleton_t *skeleton;
3148 PRVM_G_INT(OFS_RETURN) = 0;
3149 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3151 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3153 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3156 // #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)
3157 static void VM_SV_skel_get_boneparent(void)
3159 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3160 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3161 skeleton_t *skeleton;
3162 PRVM_G_FLOAT(OFS_RETURN) = 0;
3163 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3165 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3167 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3170 // #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
3171 static void VM_SV_skel_find_bone(void)
3173 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3174 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3175 skeleton_t *skeleton;
3176 PRVM_G_FLOAT(OFS_RETURN) = 0;
3177 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3179 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3182 // #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)
3183 static void VM_SV_skel_get_bonerel(void)
3185 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3186 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3187 skeleton_t *skeleton;
3189 vec3_t forward, left, up, origin;
3190 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3191 VectorClear(prog->globals.client->v_forward);
3192 VectorClear(prog->globals.client->v_right);
3193 VectorClear(prog->globals.client->v_up);
3194 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3196 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3198 matrix = skeleton->relativetransforms[bonenum];
3199 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3200 VectorCopy(forward, prog->globals.client->v_forward);
3201 VectorNegate(left, prog->globals.client->v_right);
3202 VectorCopy(up, prog->globals.client->v_up);
3203 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3206 // #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)
3207 static void VM_SV_skel_get_boneabs(void)
3209 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3210 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3211 skeleton_t *skeleton;
3214 vec3_t forward, left, up, origin;
3215 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3216 VectorClear(prog->globals.client->v_forward);
3217 VectorClear(prog->globals.client->v_right);
3218 VectorClear(prog->globals.client->v_up);
3219 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3221 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3223 matrix = skeleton->relativetransforms[bonenum];
3224 // convert to absolute
3225 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3228 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3230 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3231 VectorCopy(forward, prog->globals.client->v_forward);
3232 VectorNegate(left, prog->globals.client->v_right);
3233 VectorCopy(up, prog->globals.client->v_up);
3234 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3237 // #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)
3238 static void VM_SV_skel_set_bone(void)
3240 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3241 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3242 vec3_t forward, left, up, origin;
3243 skeleton_t *skeleton;
3245 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3247 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3249 VectorCopy(prog->globals.client->v_forward, forward);
3250 VectorNegate(prog->globals.client->v_right, left);
3251 VectorCopy(prog->globals.client->v_up, up);
3252 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3253 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3254 skeleton->relativetransforms[bonenum] = matrix;
3257 // #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)
3258 static void VM_SV_skel_mul_bone(void)
3260 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3261 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3262 vec3_t forward, left, up, origin;
3263 skeleton_t *skeleton;
3266 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3268 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3270 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3271 VectorCopy(prog->globals.client->v_forward, forward);
3272 VectorNegate(prog->globals.client->v_right, left);
3273 VectorCopy(prog->globals.client->v_up, up);
3274 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3275 temp = skeleton->relativetransforms[bonenum];
3276 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3279 // #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)
3280 static void VM_SV_skel_mul_bones(void)
3282 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3283 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3284 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3286 vec3_t forward, left, up, origin;
3287 skeleton_t *skeleton;
3290 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3292 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3293 VectorCopy(prog->globals.client->v_forward, forward);
3294 VectorNegate(prog->globals.client->v_right, left);
3295 VectorCopy(prog->globals.client->v_up, up);
3296 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3297 firstbone = max(0, firstbone);
3298 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3299 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3301 temp = skeleton->relativetransforms[bonenum];
3302 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3306 // #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
3307 static void VM_SV_skel_copybones(void)
3309 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3310 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3311 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3312 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3314 skeleton_t *skeletondst;
3315 skeleton_t *skeletonsrc;
3316 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3318 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3320 firstbone = max(0, firstbone);
3321 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3322 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3323 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3324 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3327 // #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)
3328 static void VM_SV_skel_delete(void)
3330 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3331 skeleton_t *skeleton;
3332 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3335 prog->skeletons[skeletonindex] = NULL;
3338 // #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
3339 static void VM_SV_frameforname(void)
3341 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3342 dp_model_t *model = SV_GetModelByIndex(modelindex);
3343 const char *name = PRVM_G_STRING(OFS_PARM1);
3345 PRVM_G_FLOAT(OFS_RETURN) = -1;
3346 if (!model || !model->animscenes)
3348 for (i = 0;i < model->numframes;i++)
3350 if (!strcasecmp(model->animscenes[i].name, name))
3352 PRVM_G_FLOAT(OFS_RETURN) = i;
3358 // #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.
3359 static void VM_SV_frameduration(void)
3361 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3362 dp_model_t *model = SV_GetModelByIndex(modelindex);
3363 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3364 PRVM_G_FLOAT(OFS_RETURN) = 0;
3365 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3367 if (model->animscenes[framenum].framerate)
3368 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3372 prvm_builtin_t vm_sv_builtins[] = {
3373 NULL, // #0 NULL function (not callable) (QUAKE)
3374 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3375 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3376 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3377 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3378 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3379 VM_break, // #6 void() break (QUAKE)
3380 VM_random, // #7 float() random (QUAKE)
3381 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3382 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3383 VM_error, // #10 void(string e) error (QUAKE)
3384 VM_objerror, // #11 void(string e) objerror (QUAKE)
3385 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3386 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3387 VM_spawn, // #14 entity() spawn (QUAKE)
3388 VM_remove, // #15 void(entity e) remove (QUAKE)
3389 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3390 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3391 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3392 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3393 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3394 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3395 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3396 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3397 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3398 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3399 VM_ftos, // #26 string(float f) ftos (QUAKE)
3400 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3401 VM_coredump, // #28 void() coredump (QUAKE)
3402 VM_traceon, // #29 void() traceon (QUAKE)
3403 VM_traceoff, // #30 void() traceoff (QUAKE)
3404 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3405 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3406 NULL, // #33 (QUAKE)
3407 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3408 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3409 VM_rint, // #36 float(float v) rint (QUAKE)
3410 VM_floor, // #37 float(float v) floor (QUAKE)
3411 VM_ceil, // #38 float(float v) ceil (QUAKE)
3412 NULL, // #39 (QUAKE)
3413 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3414 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3415 NULL, // #42 (QUAKE)
3416 VM_fabs, // #43 float(float f) fabs (QUAKE)
3417 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3418 VM_cvar, // #45 float(string s) cvar (QUAKE)
3419 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3420 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3421 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3422 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3423 NULL, // #50 (QUAKE)
3424 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3425 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3426 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3427 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3428 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3429 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3430 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3431 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3432 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3433 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3434 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3435 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3436 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3437 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3438 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3439 NULL, // #66 (QUAKE)
3440 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3441 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3442 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3443 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3444 NULL, // #71 (QUAKE)
3445 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3446 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3447 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3448 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3449 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3450 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3451 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3452 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3453 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3454 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3455 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3456 NULL, // #83 (QUAKE)
3457 NULL, // #84 (QUAKE)
3458 NULL, // #85 (QUAKE)
3459 NULL, // #86 (QUAKE)
3460 NULL, // #87 (QUAKE)
3461 NULL, // #88 (QUAKE)
3462 NULL, // #89 (QUAKE)
3463 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3464 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3465 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3466 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3467 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3468 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3469 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3470 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3471 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3472 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3473 // FrikaC and Telejano range #100-#199
3484 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3485 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3486 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3487 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3488 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3489 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3490 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3491 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3492 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3493 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3574 // FTEQW range #200-#299
3593 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3596 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3597 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3598 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3599 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3600 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3601 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3602 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3603 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3604 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3605 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3607 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3615 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3638 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.
3639 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
3640 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3641 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3642 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)
3643 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
3644 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)
3645 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)
3646 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)
3647 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)
3648 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)
3649 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
3650 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)
3651 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
3652 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.
3675 // CSQC range #300-#399
3676 NULL, // #300 void() clearscene (EXT_CSQC)
3677 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3678 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3679 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3680 NULL, // #304 void() renderscene (EXT_CSQC)
3681 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3682 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3683 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3684 NULL, // #308 void() R_EndPolygon
3686 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3687 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3691 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3692 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3693 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3694 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3695 NULL, // #319 void(string name) freepic (EXT_CSQC)
3696 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3697 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3698 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3699 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3700 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3701 NULL, // #325 void(void) drawresetcliparea
3706 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3707 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3708 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3709 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3710 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3711 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3712 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3713 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3714 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3715 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3716 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3717 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3718 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3719 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3720 NULL, // #344 vector() getmousepos (EXT_CSQC)
3721 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3722 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3723 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3724 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3725 NULL, // #349 float() isdemo (EXT_CSQC)
3726 VM_isserver, // #350 float() isserver (EXT_CSQC)
3727 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3728 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3729 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3730 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3736 NULL, // #360 float() readbyte (EXT_CSQC)
3737 NULL, // #361 float() readchar (EXT_CSQC)
3738 NULL, // #362 float() readshort (EXT_CSQC)
3739 NULL, // #363 float() readlong (EXT_CSQC)
3740 NULL, // #364 float() readcoord (EXT_CSQC)
3741 NULL, // #365 float() readangle (EXT_CSQC)
3742 NULL, // #366 string() readstring (EXT_CSQC)
3743 NULL, // #367 float() readfloat (EXT_CSQC)
3776 // LordHavoc's range #400-#499
3777 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3778 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3779 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3780 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3781 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3782 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3783 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3784 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3785 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)
3786 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3787 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3788 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3789 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3790 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3791 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3792 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3793 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3794 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3795 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3796 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3797 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3798 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3799 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3800 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3801 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3802 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3803 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3804 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3805 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3806 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3807 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3808 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3809 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3810 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3811 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3812 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3813 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3814 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3815 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3816 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3817 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3818 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3819 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3820 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3821 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3822 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3823 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3824 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3825 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3826 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3827 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3828 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3829 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3830 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3831 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3832 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3833 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3834 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3836 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3837 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3838 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3839 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3840 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3841 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3842 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3843 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3844 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3845 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3846 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3848 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3849 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3850 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3851 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3852 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3853 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3854 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3855 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3856 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3857 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3858 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3859 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3860 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3861 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3862 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3863 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3871 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3872 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3873 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3874 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3875 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3876 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3877 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3878 VM_SV_WritePicture, // #501
3880 VM_whichpack, // #503 string(string) whichpack = #503;
3887 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3888 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3889 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3890 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3891 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3892 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3893 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3894 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3895 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3896 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3906 VM_loadfromdata, // #529
3907 VM_loadfromfile, // #530
3908 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3982 VM_callfunction, // #605
3983 VM_writetofile, // #606
3984 VM_isfunction, // #607
3990 VM_parseentitydata, // #613
4001 VM_SV_getextresponse, // #624 string getextresponse(void)
4004 VM_sprintf, // #627 string sprintf(string format, ...)
4008 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4010 void VM_SV_Cmd_Init(void)
4015 void VM_SV_Cmd_Reset(void)
4017 World_End(&sv.world);
4018 if(prog->funcoffsets.SV_Shutdown)
4020 func_t s = prog->funcoffsets.SV_Shutdown;
4021 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4022 PRVM_ExecuteProgram(s,"SV_Shutdown() required");