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));
1402 static void VM_SV_WriteEntity (void)
1404 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1405 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1408 static void VM_SV_WriteByteINT (void)
1410 VM_SAFEPARMCOUNT(2, VM_SV_WriteByteINT);
1411 MSG_WriteByte (WriteDest(), PRVM_G_INT(OFS_PARM1));
1414 static void VM_SV_WriteCharINT (void)
1416 VM_SAFEPARMCOUNT(2, VM_SV_WriteCharINT);
1417 MSG_WriteChar (WriteDest(), PRVM_G_INT(OFS_PARM1));
1420 static void VM_SV_WriteShortINT (void)
1422 VM_SAFEPARMCOUNT(2, VM_SV_WriteShortINT);
1423 MSG_WriteShort (WriteDest(), PRVM_G_INT(OFS_PARM1));
1426 static void VM_SV_WriteLongINT (void)
1428 VM_SAFEPARMCOUNT(2, VM_SV_WriteLongINT);
1429 MSG_WriteLong (WriteDest(), PRVM_G_INT(OFS_PARM1));
1433 // writes a picture as at most size bytes of data
1435 // IMGNAME \0 SIZE(short) IMGDATA
1436 // if failed to read/compress:
1438 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1439 static void VM_SV_WritePicture (void)
1441 const char *imgname;
1445 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1447 imgname = PRVM_G_STRING(OFS_PARM1);
1448 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1452 MSG_WriteString(WriteDest(), imgname);
1453 if(Image_Compress(imgname, size, &buf, &size))
1456 MSG_WriteShort(WriteDest(), size);
1457 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1462 MSG_WriteShort(WriteDest(), 0);
1466 //////////////////////////////////////////////////////////
1468 static void VM_SV_makestatic (void)
1473 // allow 0 parameters due to an id1 qc bug in which this function is used
1474 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1475 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1477 if (prog->argc >= 1)
1478 ent = PRVM_G_EDICT(OFS_PARM0);
1480 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1481 if (ent == prog->edicts)
1483 VM_Warning("makestatic: can not modify world entity\n");
1486 if (ent->priv.server->free)
1488 VM_Warning("makestatic: can not modify free entity\n");
1493 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1498 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1499 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1500 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1502 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1504 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1505 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1506 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1510 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1511 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1512 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1515 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1516 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1517 for (i=0 ; i<3 ; i++)
1519 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1520 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1523 // throw the entity away now
1527 //=============================================================================
1534 static void VM_SV_setspawnparms (void)
1540 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1542 ent = PRVM_G_EDICT(OFS_PARM0);
1543 i = PRVM_NUM_FOR_EDICT(ent);
1544 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1546 Con_Print("tried to setspawnparms on a non-client\n");
1550 // copy spawn parms out of the client_t
1551 client = svs.clients + i-1;
1552 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1553 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1560 Returns a color vector indicating the lighting at the requested point.
1562 (Internal Operation note: actually measures the light beneath the point, just like
1563 the model lighting on the client)
1568 static void VM_SV_getlight (void)
1570 vec3_t ambientcolor, diffusecolor, diffusenormal;
1572 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1573 p = PRVM_G_VECTOR(OFS_PARM0);
1574 VectorClear(ambientcolor);
1575 VectorClear(diffusecolor);
1576 VectorClear(diffusenormal);
1577 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1578 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1579 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1584 unsigned char type; // 1/2/8 or other value if isn't used
1588 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1589 static int vm_customstats_last;
1591 void VM_CustomStats_Clear (void)
1595 Z_Free(vm_customstats);
1596 vm_customstats = NULL;
1597 vm_customstats_last = -1;
1601 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1609 for(i=0; i<vm_customstats_last+1 ;i++)
1611 if(!vm_customstats[i].type)
1613 switch(vm_customstats[i].type)
1615 //string as 16 bytes
1618 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1619 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1620 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1621 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1622 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1624 //float field sent as-is
1626 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1628 //integer value of float field
1630 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1638 // void(float index, float type, .void field) SV_AddStat = #232;
1639 // Set up an auto-sent player stat.
1640 // Client's get thier own fields sent to them. Index may not be less than 32.
1641 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1642 // 1: string (4 stats carrying a total of 16 charactures)
1643 // 2: float (one stat, float converted to an integer for transportation)
1644 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1645 static void VM_SV_AddStat (void)
1650 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1654 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1657 VM_Warning("PF_SV_AddStat: not enough memory\n");
1661 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1662 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1663 off = PRVM_G_INT (OFS_PARM2);
1668 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1671 if(i >= (MAX_CL_STATS-32))
1673 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1676 if(i > (MAX_CL_STATS-32-4) && type == 1)
1678 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1681 vm_customstats[i].type = type;
1682 vm_customstats[i].fieldoffset = off;
1683 if(vm_customstats_last < i)
1684 vm_customstats_last = i;
1691 copies data from one entity to another
1693 copyentity(src, dst)
1696 static void VM_SV_copyentity (void)
1698 prvm_edict_t *in, *out;
1699 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1700 in = PRVM_G_EDICT(OFS_PARM0);
1701 if (in == prog->edicts)
1703 VM_Warning("copyentity: can not read world entity\n");
1706 if (in->priv.server->free)
1708 VM_Warning("copyentity: can not read free entity\n");
1711 out = PRVM_G_EDICT(OFS_PARM1);
1712 if (out == prog->edicts)
1714 VM_Warning("copyentity: can not modify world entity\n");
1717 if (out->priv.server->free)
1719 VM_Warning("copyentity: can not modify free entity\n");
1722 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1731 sets the color of a client and broadcasts the update to all connected clients
1733 setcolor(clientent, value)
1736 static void VM_SV_setcolor (void)
1742 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1743 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1744 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1746 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1748 Con_Print("tried to setcolor a non-client\n");
1752 client = svs.clients + entnum-1;
1755 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1757 client->edict->fields.server->team = (i & 15) + 1;
1760 if (client->old_colors != client->colors)
1762 client->old_colors = client->colors;
1763 // send notification to all clients
1764 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1765 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1766 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1774 effect(origin, modelname, startframe, framecount, framerate)
1777 static void VM_SV_effect (void)
1781 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1782 s = PRVM_G_STRING(OFS_PARM1);
1785 VM_Warning("effect: no model specified\n");
1789 i = SV_ModelIndex(s, 1);
1792 VM_Warning("effect: model not precached\n");
1796 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1798 VM_Warning("effect: framecount < 1\n");
1802 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1804 VM_Warning("effect: framerate < 1\n");
1808 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));
1811 static void VM_SV_te_blood (void)
1813 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1814 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1816 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1817 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1819 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1820 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1821 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1823 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1824 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1825 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1827 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1828 SV_FlushBroadcastMessages();
1831 static void VM_SV_te_bloodshower (void)
1833 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1834 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1836 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1837 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1839 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1840 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1841 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1843 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1844 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1845 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1847 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1849 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1850 SV_FlushBroadcastMessages();
1853 static void VM_SV_te_explosionrgb (void)
1855 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1856 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1857 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1859 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1860 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1861 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1863 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1864 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1865 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1866 SV_FlushBroadcastMessages();
1869 static void VM_SV_te_particlecube (void)
1871 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1872 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1874 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1875 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1877 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1878 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1879 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1881 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1882 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1885 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1886 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1887 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1889 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1891 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1892 // gravity true/false
1893 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1895 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1896 SV_FlushBroadcastMessages();
1899 static void VM_SV_te_particlerain (void)
1901 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1902 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1904 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1905 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1908 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1909 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1912 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1913 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1915 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1916 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1917 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1919 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1921 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1922 SV_FlushBroadcastMessages();
1925 static void VM_SV_te_particlesnow (void)
1927 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1928 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1930 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1931 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1933 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1934 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1935 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1937 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1938 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1939 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1941 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1942 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1943 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1945 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1947 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1948 SV_FlushBroadcastMessages();
1951 static void VM_SV_te_spark (void)
1953 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1954 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1956 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1957 MSG_WriteByte(&sv.datagram, TE_SPARK);
1959 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1960 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1961 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1963 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1964 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1965 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1967 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1968 SV_FlushBroadcastMessages();
1971 static void VM_SV_te_gunshotquad (void)
1973 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1974 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1975 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
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_spikequad (void)
1985 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
1986 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1987 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
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_superspikequad (void)
1997 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
1998 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1999 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
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_explosionquad (void)
2009 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2010 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2011 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2013 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2014 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2015 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2016 SV_FlushBroadcastMessages();
2019 static void VM_SV_te_smallflash (void)
2021 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2022 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2023 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2025 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2026 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2027 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2028 SV_FlushBroadcastMessages();
2031 static void VM_SV_te_customflash (void)
2033 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2034 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2036 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2037 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2039 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2040 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2041 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2043 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2045 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2047 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2048 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2049 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2050 SV_FlushBroadcastMessages();
2053 static void VM_SV_te_gunshot (void)
2055 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2056 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2057 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
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_spike (void)
2067 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2068 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2069 MSG_WriteByte(&sv.datagram, TE_SPIKE);
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_superspike (void)
2079 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2080 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2081 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
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_explosion (void)
2091 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2092 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2093 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
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_tarexplosion (void)
2103 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2104 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2105 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
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_wizspike (void)
2115 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2116 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2117 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
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_knightspike (void)
2127 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2128 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2129 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
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_lavasplash (void)
2139 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2140 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2141 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
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);
2146 SV_FlushBroadcastMessages();
2149 static void VM_SV_te_teleport (void)
2151 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2152 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2153 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2155 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2156 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2157 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2158 SV_FlushBroadcastMessages();
2161 static void VM_SV_te_explosion2 (void)
2163 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2164 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2165 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2167 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2168 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2169 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2171 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2172 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2173 SV_FlushBroadcastMessages();
2176 static void VM_SV_te_lightning1 (void)
2178 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2179 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2180 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2182 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2185 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2186 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2188 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2189 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2190 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2191 SV_FlushBroadcastMessages();
2194 static void VM_SV_te_lightning2 (void)
2196 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2197 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2198 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2200 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2202 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2203 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2204 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2206 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2207 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2208 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2209 SV_FlushBroadcastMessages();
2212 static void VM_SV_te_lightning3 (void)
2214 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2215 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2216 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2218 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2221 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2222 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2224 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2225 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2226 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2227 SV_FlushBroadcastMessages();
2230 static void VM_SV_te_beam (void)
2232 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2233 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2234 MSG_WriteByte(&sv.datagram, TE_BEAM);
2236 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2238 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2239 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2240 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2244 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2245 SV_FlushBroadcastMessages();
2248 static void VM_SV_te_plasmaburn (void)
2250 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2251 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2252 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2253 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2254 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2255 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2256 SV_FlushBroadcastMessages();
2259 static void VM_SV_te_flamejet (void)
2261 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2262 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2263 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2265 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2266 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2267 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2273 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2274 SV_FlushBroadcastMessages();
2277 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2280 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2282 bestdist = 1000000000;
2284 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2286 // clip original point to each triangle of the surface and find the
2287 // triangle that is closest
2288 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2289 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2290 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2291 TriangleNormal(v[0], v[1], v[2], facenormal);
2292 VectorNormalize(facenormal);
2293 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2294 VectorMA(p, offsetdist, facenormal, temp);
2295 for (j = 0, k = 2;j < 3;k = j, j++)
2297 VectorSubtract(v[k], v[j], edgenormal);
2298 CrossProduct(edgenormal, facenormal, sidenormal);
2299 VectorNormalize(sidenormal);
2300 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2302 VectorMA(temp, offsetdist, sidenormal, temp);
2304 dist = VectorDistance2(temp, p);
2305 if (bestdist > dist)
2308 VectorCopy(temp, out);
2313 #define getmodel SV_GetModelFromEdict
2315 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2317 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2319 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2323 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2324 static void VM_SV_getsurfacenumpoints(void)
2327 msurface_t *surface;
2328 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2329 // return 0 if no such surface
2330 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2332 PRVM_G_FLOAT(OFS_RETURN) = 0;
2336 // note: this (incorrectly) assumes it is a simple polygon
2337 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2339 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2340 static void VM_SV_getsurfacepoint(void)
2344 msurface_t *surface;
2346 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2347 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2348 ed = PRVM_G_EDICT(OFS_PARM0);
2349 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2351 // note: this (incorrectly) assumes it is a simple polygon
2352 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2353 if (pointnum < 0 || pointnum >= surface->num_vertices)
2355 // FIXME: implement rotation/scaling
2356 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2358 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2359 // float SPA_POSITION = 0;
2360 // float SPA_S_AXIS = 1;
2361 // float SPA_T_AXIS = 2;
2362 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2363 // float SPA_TEXCOORDS0 = 4;
2364 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2365 // float SPA_LIGHTMAP0_COLOR = 6;
2366 static void VM_SV_getsurfacepointattribute(void)
2370 msurface_t *surface;
2374 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2375 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2376 ed = PRVM_G_EDICT(OFS_PARM0);
2377 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2379 // note: this (incorrectly) assumes it is a simple polygon
2380 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2381 if (pointnum < 0 || pointnum >= surface->num_vertices)
2383 // FIXME: implement rotation/scaling
2384 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2386 switch( attributetype ) {
2387 // float SPA_POSITION = 0;
2389 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2391 // float SPA_S_AXIS = 1;
2393 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2395 // float SPA_T_AXIS = 2;
2397 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2399 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2401 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2403 // float SPA_TEXCOORDS0 = 4;
2405 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2406 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2407 ret[0] = texcoord[0];
2408 ret[1] = texcoord[1];
2412 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2414 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2415 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2416 ret[0] = texcoord[0];
2417 ret[1] = texcoord[1];
2421 // float SPA_LIGHTMAP0_COLOR = 6;
2423 // ignore alpha for now..
2424 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2427 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2431 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2432 static void VM_SV_getsurfacenormal(void)
2435 msurface_t *surface;
2437 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2438 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2439 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2441 // FIXME: implement rotation/scaling
2442 // note: this (incorrectly) assumes it is a simple polygon
2443 // note: this only returns the first triangle, so it doesn't work very
2444 // well for curved surfaces or arbitrary meshes
2445 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);
2446 VectorNormalize(normal);
2447 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2449 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2450 static void VM_SV_getsurfacetexture(void)
2453 msurface_t *surface;
2454 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2455 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2456 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2458 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2460 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2461 static void VM_SV_getsurfacenearpoint(void)
2463 int surfacenum, best;
2465 vec_t dist, bestdist;
2468 msurface_t *surface;
2470 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2471 PRVM_G_FLOAT(OFS_RETURN) = -1;
2472 ed = PRVM_G_EDICT(OFS_PARM0);
2473 point = PRVM_G_VECTOR(OFS_PARM1);
2475 if (!ed || ed->priv.server->free)
2477 model = getmodel(ed);
2478 if (!model || !model->num_surfaces)
2481 // FIXME: implement rotation/scaling
2482 VectorSubtract(point, ed->fields.server->origin, p);
2484 bestdist = 1000000000;
2485 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2487 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2488 // first see if the nearest point on the surface's box is closer than the previous match
2489 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2490 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2491 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2492 dist = VectorLength2(clipped);
2493 if (dist < bestdist)
2495 // it is, check the nearest point on the actual geometry
2496 clippointtosurface(model, surface, p, clipped);
2497 VectorSubtract(clipped, p, clipped);
2498 dist += VectorLength2(clipped);
2499 if (dist < bestdist)
2501 // that's closer too, store it as the best match
2507 PRVM_G_FLOAT(OFS_RETURN) = best;
2509 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2510 static void VM_SV_getsurfaceclippedpoint(void)
2514 msurface_t *surface;
2516 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2517 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2518 ed = PRVM_G_EDICT(OFS_PARM0);
2519 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2521 // FIXME: implement rotation/scaling
2522 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2523 clippointtosurface(model, surface, p, out);
2524 // FIXME: implement rotation/scaling
2525 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2528 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2529 //this function originally written by KrimZon, made shorter by LordHavoc
2530 static void VM_SV_clientcommand (void)
2532 client_t *temp_client;
2534 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2536 //find client for this entity
2537 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2538 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2540 Con_Print("PF_clientcommand: entity is not a client\n");
2544 temp_client = host_client;
2545 host_client = svs.clients + i;
2546 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2547 host_client = temp_client;
2550 //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)
2551 static void VM_SV_setattachment (void)
2553 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2554 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2555 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2558 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2560 if (e == prog->edicts)
2562 VM_Warning("setattachment: can not modify world entity\n");
2565 if (e->priv.server->free)
2567 VM_Warning("setattachment: can not modify free entity\n");
2571 if (tagentity == NULL)
2572 tagentity = prog->edicts;
2574 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2576 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2578 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2581 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2583 model = SV_GetModelFromEdict(tagentity);
2586 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2588 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);
2591 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));
2595 /////////////////////////////////////////
2596 // DP_MD3_TAGINFO extension coded by VorteX
2598 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2602 i = (int)e->fields.server->modelindex;
2603 if (i < 1 || i >= MAX_MODELS)
2606 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2609 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2616 Matrix4x4_CreateIdentity(tag_localmatrix);
2618 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2620 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2631 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2635 float pitchsign = 1;
2638 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2639 if (val && val->_float != 0)
2640 scale = val->_float;
2643 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);
2646 pitchsign = SV_GetPitchSign(ent);
2647 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);
2651 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2654 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
2656 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2657 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2658 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2659 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2661 *out = identitymatrix;
2665 // Warnings/errors code:
2666 // 0 - normal (everything all-right)
2669 // 3 - null or non-precached model
2670 // 4 - no tags with requested index
2671 // 5 - runaway loop at attachment chain
2672 extern cvar_t cl_bob;
2673 extern cvar_t cl_bobcycle;
2674 extern cvar_t cl_bobup;
2675 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2679 int modelindex, attachloop;
2680 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2683 *out = identitymatrix; // warnings and errors return identical matrix
2685 if (ent == prog->edicts)
2687 if (ent->priv.server->free)
2690 modelindex = (int)ent->fields.server->modelindex;
2691 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2694 model = SV_GetModelByIndex(modelindex);
2696 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2697 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2698 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2700 tagmatrix = identitymatrix;
2701 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2705 if (attachloop >= 256) // prevent runaway looping
2707 // apply transformation by child's tagindex on parent entity and then
2708 // by parent entity itself
2709 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2710 if (ret && attachloop == 0)
2712 SV_GetEntityMatrix(ent, &entitymatrix, false);
2713 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2714 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2715 // next iteration we process the parent entity
2716 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2718 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2719 ent = PRVM_EDICT_NUM(val->edict);
2726 // RENDER_VIEWMODEL magic
2727 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2729 Matrix4x4_Copy(&tagmatrix, out);
2730 ent = PRVM_EDICT_NUM(val->edict);
2732 SV_GetEntityMatrix(ent, &entitymatrix, true);
2733 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2736 // Cl_bob, ported from rendering code
2737 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2740 // LordHavoc: this code is *weird*, but not replacable (I think it
2741 // should be done in QC on the server, but oh well, quake is quake)
2742 // LordHavoc: figured out bobup: the time at which the sin is at 180
2743 // degrees (which allows lengthening or squishing the peak or valley)
2744 cycle = sv.time/cl_bobcycle.value;
2745 cycle -= (int)cycle;
2746 if (cycle < cl_bobup.value)
2747 cycle = sin(M_PI * cycle / cl_bobup.value);
2749 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2750 // bob is proportional to velocity in the xy plane
2751 // (don't count Z, or jumping messes it up)
2752 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;
2753 bob = bob*0.3 + bob*0.7*cycle;
2754 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2761 //float(entity ent, string tagname) gettagindex;
2763 static void VM_SV_gettagindex (void)
2766 const char *tag_name;
2769 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2771 ent = PRVM_G_EDICT(OFS_PARM0);
2772 tag_name = PRVM_G_STRING(OFS_PARM1);
2774 if (ent == prog->edicts)
2776 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2779 if (ent->priv.server->free)
2781 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2786 if (!SV_GetModelFromEdict(ent))
2787 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2790 tag_index = SV_GetTagIndex(ent, tag_name);
2792 if(developer_extra.integer)
2793 Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2795 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2798 //vector(entity ent, float tagindex) gettaginfo;
2799 static void VM_SV_gettaginfo (void)
2803 matrix4x4_t tag_matrix;
2804 matrix4x4_t tag_localmatrix;
2806 const char *tagname;
2809 vec3_t fo, le, up, trans;
2810 const dp_model_t *model;
2812 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2814 e = PRVM_G_EDICT(OFS_PARM0);
2815 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2817 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2818 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2819 VectorScale(le, -1, prog->globals.server->v_right);
2820 model = SV_GetModelFromEdict(e);
2821 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2822 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2823 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2824 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2825 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2827 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2828 val->_float = parentindex;
2829 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2830 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2831 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2832 VectorCopy(trans, val->vector);
2833 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2834 VectorCopy(fo, val->vector);
2835 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2836 VectorScale(le, -1, val->vector);
2837 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2838 VectorCopy(up, val->vector);
2843 VM_Warning("gettagindex: can't affect world entity\n");
2846 VM_Warning("gettagindex: can't affect free entity\n");
2849 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2852 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2855 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2860 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2861 static void VM_SV_dropclient (void)
2864 client_t *oldhostclient;
2865 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2866 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2867 if (clientnum < 0 || clientnum >= svs.maxclients)
2869 VM_Warning("dropclient: not a client\n");
2872 if (!svs.clients[clientnum].active)
2874 VM_Warning("dropclient: that client slot is not connected\n");
2877 oldhostclient = host_client;
2878 host_client = svs.clients + clientnum;
2879 SV_DropClient(false);
2880 host_client = oldhostclient;
2883 //entity() spawnclient (DP_SV_BOTCLIENT)
2884 static void VM_SV_spawnclient (void)
2888 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2889 prog->xfunction->builtinsprofile += 2;
2891 for (i = 0;i < svs.maxclients;i++)
2893 if (!svs.clients[i].active)
2895 prog->xfunction->builtinsprofile += 100;
2896 SV_ConnectClient (i, NULL);
2897 // this has to be set or else ClientDisconnect won't be called
2898 // we assume the qc will call ClientConnect...
2899 svs.clients[i].clientconnectcalled = true;
2900 ed = PRVM_EDICT_NUM(i + 1);
2904 VM_RETURN_EDICT(ed);
2907 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2908 static void VM_SV_clienttype (void)
2911 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2912 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2913 if (clientnum < 0 || clientnum >= svs.maxclients)
2914 PRVM_G_FLOAT(OFS_RETURN) = 3;
2915 else if (!svs.clients[clientnum].active)
2916 PRVM_G_FLOAT(OFS_RETURN) = 0;
2917 else if (svs.clients[clientnum].netconnection)
2918 PRVM_G_FLOAT(OFS_RETURN) = 1;
2920 PRVM_G_FLOAT(OFS_RETURN) = 2;
2927 string(string key) serverkey
2930 void VM_SV_serverkey(void)
2932 char string[VM_STRINGTEMP_LENGTH];
2933 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2934 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2935 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2938 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2939 static void VM_SV_setmodelindex (void)
2944 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2946 e = PRVM_G_EDICT(OFS_PARM0);
2947 if (e == prog->edicts)
2949 VM_Warning("setmodelindex: can not modify world entity\n");
2952 if (e->priv.server->free)
2954 VM_Warning("setmodelindex: can not modify free entity\n");
2957 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2958 if (i <= 0 || i >= MAX_MODELS)
2960 VM_Warning("setmodelindex: invalid modelindex\n");
2963 if (!sv.model_precache[i][0])
2965 VM_Warning("setmodelindex: model not precached\n");
2969 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2970 e->fields.server->modelindex = i;
2972 mod = SV_GetModelByIndex(i);
2976 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2977 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2979 SetMinMaxSize (e, quakemins, quakemaxs, true);
2982 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
2985 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2986 static void VM_SV_modelnameforindex (void)
2989 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2991 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2993 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2994 if (i <= 0 || i >= MAX_MODELS)
2996 VM_Warning("modelnameforindex: invalid modelindex\n");
2999 if (!sv.model_precache[i][0])
3001 VM_Warning("modelnameforindex: model not precached\n");
3005 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
3008 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
3009 static void VM_SV_particleeffectnum (void)
3012 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
3013 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
3016 PRVM_G_FLOAT(OFS_RETURN) = i;
3019 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3020 static void VM_SV_trailparticles (void)
3022 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
3024 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3027 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3028 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3029 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3030 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3031 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3032 SV_FlushBroadcastMessages();
3035 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3036 static void VM_SV_pointparticles (void)
3038 int effectnum, count;
3040 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3042 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3045 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3046 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3047 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3048 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3049 if (count == 1 && !VectorLength2(vel))
3052 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3053 MSG_WriteShort(&sv.datagram, effectnum);
3054 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3058 // 1+2+12+12+2=29 bytes
3059 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3060 MSG_WriteShort(&sv.datagram, effectnum);
3061 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3062 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3063 MSG_WriteShort(&sv.datagram, count);
3066 SV_FlushBroadcastMessages();
3069 //PF_setpause, // void(float pause) setpause = #531;
3070 static void VM_SV_setpause(void) {
3072 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3073 if (pauseValue != 0) { //pause the game
3075 sv.pausedstart = Sys_DoubleTime();
3076 } else { //disable pause, in case it was enabled
3077 if (sv.paused != 0) {
3082 // send notification to all clients
3083 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3084 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3087 // #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.
3088 static void VM_SV_skel_create(void)
3090 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3091 dp_model_t *model = SV_GetModelByIndex(modelindex);
3092 skeleton_t *skeleton;
3094 PRVM_G_FLOAT(OFS_RETURN) = 0;
3095 if (!model || !model->num_bones)
3097 for (i = 0;i < MAX_EDICTS;i++)
3098 if (!prog->skeletons[i])
3100 if (i == MAX_EDICTS)
3102 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3103 skeleton->model = model;
3104 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3105 // initialize to identity matrices
3106 for (i = 0;i < skeleton->model->num_bones;i++)
3107 skeleton->relativetransforms[i] = identitymatrix;
3108 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3111 // #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
3112 static void VM_SV_skel_build(void)
3114 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3115 skeleton_t *skeleton;
3116 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3117 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3118 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3119 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3120 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3121 dp_model_t *model = SV_GetModelByIndex(modelindex);
3126 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3127 frameblend_t frameblend[MAX_FRAMEBLENDS];
3128 matrix4x4_t blendedmatrix;
3130 PRVM_G_FLOAT(OFS_RETURN) = 0;
3131 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3133 firstbone = max(0, firstbone);
3134 lastbone = min(lastbone, model->num_bones - 1);
3135 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3136 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3137 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3138 blendfrac = 1.0f - retainfrac;
3139 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3140 frameblend[numblends].lerp *= blendfrac;
3141 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3143 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3144 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3145 for (blendindex = 0;blendindex < numblends;blendindex++)
3147 Matrix4x4_FromBonePose6s(&matrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3148 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3150 skeleton->relativetransforms[bonenum] = blendedmatrix;
3152 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3155 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3156 static void VM_SV_skel_get_numbones(void)
3158 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3159 skeleton_t *skeleton;
3160 PRVM_G_FLOAT(OFS_RETURN) = 0;
3161 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3163 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3166 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3167 static void VM_SV_skel_get_bonename(void)
3169 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3170 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3171 skeleton_t *skeleton;
3172 PRVM_G_INT(OFS_RETURN) = 0;
3173 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3175 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3177 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3180 // #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)
3181 static void VM_SV_skel_get_boneparent(void)
3183 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3184 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3185 skeleton_t *skeleton;
3186 PRVM_G_FLOAT(OFS_RETURN) = 0;
3187 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3189 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3191 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3194 // #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
3195 static void VM_SV_skel_find_bone(void)
3197 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3198 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3199 skeleton_t *skeleton;
3200 PRVM_G_FLOAT(OFS_RETURN) = 0;
3201 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3203 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3206 // #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)
3207 static void VM_SV_skel_get_bonerel(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;
3213 vec3_t forward, left, up, origin;
3214 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3215 VectorClear(prog->globals.client->v_forward);
3216 VectorClear(prog->globals.client->v_right);
3217 VectorClear(prog->globals.client->v_up);
3218 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3220 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3222 matrix = skeleton->relativetransforms[bonenum];
3223 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3224 VectorCopy(forward, prog->globals.client->v_forward);
3225 VectorNegate(left, prog->globals.client->v_right);
3226 VectorCopy(up, prog->globals.client->v_up);
3227 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3230 // #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)
3231 static void VM_SV_skel_get_boneabs(void)
3233 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3234 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3235 skeleton_t *skeleton;
3238 vec3_t forward, left, up, origin;
3239 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3240 VectorClear(prog->globals.client->v_forward);
3241 VectorClear(prog->globals.client->v_right);
3242 VectorClear(prog->globals.client->v_up);
3243 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3245 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3247 matrix = skeleton->relativetransforms[bonenum];
3248 // convert to absolute
3249 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3252 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3254 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3255 VectorCopy(forward, prog->globals.client->v_forward);
3256 VectorNegate(left, prog->globals.client->v_right);
3257 VectorCopy(up, prog->globals.client->v_up);
3258 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3261 // #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)
3262 static void VM_SV_skel_set_bone(void)
3264 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3265 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3266 vec3_t forward, left, up, origin;
3267 skeleton_t *skeleton;
3269 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3271 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3273 VectorCopy(prog->globals.client->v_forward, forward);
3274 VectorNegate(prog->globals.client->v_right, left);
3275 VectorCopy(prog->globals.client->v_up, up);
3276 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3277 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3278 skeleton->relativetransforms[bonenum] = matrix;
3281 // #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)
3282 static void VM_SV_skel_mul_bone(void)
3284 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3285 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3286 vec3_t forward, left, up, origin;
3287 skeleton_t *skeleton;
3290 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3292 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3294 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3295 VectorCopy(prog->globals.client->v_forward, forward);
3296 VectorNegate(prog->globals.client->v_right, left);
3297 VectorCopy(prog->globals.client->v_up, up);
3298 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3299 temp = skeleton->relativetransforms[bonenum];
3300 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3303 // #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)
3304 static void VM_SV_skel_mul_bones(void)
3306 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3307 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3308 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3310 vec3_t forward, left, up, origin;
3311 skeleton_t *skeleton;
3314 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3316 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3317 VectorCopy(prog->globals.client->v_forward, forward);
3318 VectorNegate(prog->globals.client->v_right, left);
3319 VectorCopy(prog->globals.client->v_up, up);
3320 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3321 firstbone = max(0, firstbone);
3322 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3323 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3325 temp = skeleton->relativetransforms[bonenum];
3326 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3330 // #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
3331 static void VM_SV_skel_copybones(void)
3333 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3334 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3335 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3336 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3338 skeleton_t *skeletondst;
3339 skeleton_t *skeletonsrc;
3340 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3342 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3344 firstbone = max(0, firstbone);
3345 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3346 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3347 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3348 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3351 // #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)
3352 static void VM_SV_skel_delete(void)
3354 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3355 skeleton_t *skeleton;
3356 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3359 prog->skeletons[skeletonindex] = NULL;
3362 // #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
3363 static void VM_SV_frameforname(void)
3365 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3366 dp_model_t *model = SV_GetModelByIndex(modelindex);
3367 const char *name = PRVM_G_STRING(OFS_PARM1);
3369 PRVM_G_FLOAT(OFS_RETURN) = -1;
3370 if (!model || !model->animscenes)
3372 for (i = 0;i < model->numframes;i++)
3374 if (!strcasecmp(model->animscenes[i].name, name))
3376 PRVM_G_FLOAT(OFS_RETURN) = i;
3382 // #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.
3383 static void VM_SV_frameduration(void)
3385 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3386 dp_model_t *model = SV_GetModelByIndex(modelindex);
3387 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3388 PRVM_G_FLOAT(OFS_RETURN) = 0;
3389 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3391 if (model->animscenes[framenum].framerate)
3392 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3396 prvm_builtin_t vm_sv_builtins[] = {
3397 NULL, // #0 NULL function (not callable) (QUAKE)
3398 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3399 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3400 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3401 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3402 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3403 VM_break, // #6 void() break (QUAKE)
3404 VM_random, // #7 float() random (QUAKE)
3405 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3406 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3407 VM_error, // #10 void(string e) error (QUAKE)
3408 VM_objerror, // #11 void(string e) objerror (QUAKE)
3409 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3410 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3411 VM_spawn, // #14 entity() spawn (QUAKE)
3412 VM_remove, // #15 void(entity e) remove (QUAKE)
3413 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3414 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3415 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3416 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3417 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3418 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3419 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3420 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3421 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3422 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3423 VM_ftos, // #26 string(float f) ftos (QUAKE)
3424 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3425 VM_coredump, // #28 void() coredump (QUAKE)
3426 VM_traceon, // #29 void() traceon (QUAKE)
3427 VM_traceoff, // #30 void() traceoff (QUAKE)
3428 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3429 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3430 NULL, // #33 (QUAKE)
3431 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3432 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3433 VM_rint, // #36 float(float v) rint (QUAKE)
3434 VM_floor, // #37 float(float v) floor (QUAKE)
3435 VM_ceil, // #38 float(float v) ceil (QUAKE)
3436 NULL, // #39 (QUAKE)
3437 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3438 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3439 NULL, // #42 (QUAKE)
3440 VM_fabs, // #43 float(float f) fabs (QUAKE)
3441 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3442 VM_cvar, // #45 float(string s) cvar (QUAKE)
3443 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3444 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3445 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3446 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3447 NULL, // #50 (QUAKE)
3448 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3449 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3450 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3451 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3452 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3453 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3454 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3455 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3456 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3457 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3458 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3459 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3460 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3461 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3462 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3463 NULL, // #66 (QUAKE)
3464 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3465 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3466 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3467 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3468 NULL, // #71 (QUAKE)
3469 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3470 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3471 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3472 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3473 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3474 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3475 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3476 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3477 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3478 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3479 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3480 NULL, // #83 (QUAKE)
3481 NULL, // #84 (QUAKE)
3482 NULL, // #85 (QUAKE)
3483 NULL, // #86 (QUAKE)
3484 NULL, // #87 (QUAKE)
3485 NULL, // #88 (QUAKE)
3486 NULL, // #89 (QUAKE)
3487 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3488 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3489 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3490 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3491 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3492 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3493 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3494 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3495 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3496 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3497 // FrikaC and Telejano range #100-#199
3508 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3509 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3510 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3511 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3512 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3513 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3514 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3515 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3516 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3517 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3598 // FTEQW range #200-#299
3617 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3620 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3621 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3622 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3623 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3624 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3625 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3626 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3627 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3628 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3629 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3631 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3639 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3662 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.
3663 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
3664 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3665 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3666 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)
3667 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
3668 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)
3669 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)
3670 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)
3671 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)
3672 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)
3673 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
3674 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)
3675 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
3676 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.
3699 // CSQC range #300-#399
3700 NULL, // #300 void() clearscene (EXT_CSQC)
3701 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3702 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3703 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3704 NULL, // #304 void() renderscene (EXT_CSQC)
3705 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3706 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3707 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3708 NULL, // #308 void() R_EndPolygon
3710 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3711 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3715 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3716 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3717 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3718 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3719 NULL, // #319 void(string name) freepic (EXT_CSQC)
3720 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3721 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3722 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3723 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3724 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3725 NULL, // #325 void(void) drawresetcliparea
3730 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3731 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3732 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3733 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3734 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3735 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3736 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3737 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3738 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3739 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3740 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3741 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3742 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3743 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3744 NULL, // #344 vector() getmousepos (EXT_CSQC)
3745 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3746 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3747 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3748 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3749 NULL, // #349 float() isdemo (EXT_CSQC)
3750 VM_isserver, // #350 float() isserver (EXT_CSQC)
3751 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3752 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3753 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3754 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3760 NULL, // #360 float() readbyte (EXT_CSQC)
3761 NULL, // #361 float() readchar (EXT_CSQC)
3762 NULL, // #362 float() readshort (EXT_CSQC)
3763 NULL, // #363 float() readlong (EXT_CSQC)
3764 NULL, // #364 float() readcoord (EXT_CSQC)
3765 NULL, // #365 float() readangle (EXT_CSQC)
3766 NULL, // #366 string() readstring (EXT_CSQC)
3767 NULL, // #367 float() readfloat (EXT_CSQC)
3800 // LordHavoc's range #400-#499
3801 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3802 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3803 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3804 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3805 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3806 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3807 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3808 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3809 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)
3810 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3811 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3812 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3813 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3814 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3815 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3816 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3817 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3818 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3819 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3820 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3821 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3822 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3823 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3824 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3825 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3826 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3827 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3828 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3829 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3830 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3831 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3832 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3833 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3834 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3835 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3836 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3837 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3838 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3839 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3840 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3841 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3842 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3843 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3844 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3845 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3846 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3847 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3848 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3849 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3850 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3851 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3852 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3853 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3854 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3855 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3856 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3857 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3858 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3860 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3861 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3862 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3863 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3864 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3865 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3866 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3867 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3868 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3869 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3870 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3872 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3873 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3874 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3875 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3876 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3877 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3878 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3879 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3880 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3881 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3882 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3883 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3884 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3885 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3886 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3887 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3895 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3896 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3897 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3898 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3899 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3900 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3901 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3902 VM_SV_WritePicture, // #501
3904 VM_whichpack, // #503 string(string) whichpack = #503;
3911 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3912 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3913 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3914 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3915 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3916 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3917 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3918 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3919 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3920 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3930 VM_loadfromdata, // #529
3931 VM_loadfromfile, // #530
3932 VM_SV_setpause, // #531 void(float pause) setpause = #531;
4006 VM_callfunction, // #605
4007 VM_writetofile, // #606
4008 VM_isfunction, // #607
4014 VM_parseentitydata, // #613
4025 VM_SV_getextresponse, // #624 string getextresponse(void)
4028 VM_sprintf, // #627 string sprintf(string format, ...)
4032 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4034 void VM_SV_Cmd_Init(void)
4039 void VM_SV_Cmd_Reset(void)
4041 World_End(&sv.world);
4042 if(prog->funcoffsets.SV_Shutdown)
4044 func_t s = prog->funcoffsets.SV_Shutdown;
4045 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4046 PRVM_ExecuteProgram(s,"SV_Shutdown() required");