6 //============================================================================
11 char *vm_sv_extensions =
16 "DP_CON_ALIASPARAMETERS "
22 "DP_CSQC_ENTITYNOCULL "
23 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
24 "DP_CSQC_MULTIFRAME_INTERPOLATION "
25 "DP_CSQC_SPAWNPARTICLE "
41 "DP_ENT_CUSTOMCOLORMAP "
42 "DP_ENT_EXTERIORMODELTOCLIENT "
45 "DP_ENT_LOWPRECISION "
49 "DP_GFX_EXTERNALTEXTURES "
50 "DP_GFX_EXTERNALTEXTURES_PERMAP "
52 "DP_GFX_MODEL_INTERPOLATION "
53 "DP_GFX_QUAKE3MODELTAGS "
57 "DP_HALFLIFE_MAP_CVAR "
60 "DP_LIGHTSTYLE_STATICVALUE "
64 "DP_MOVETYPEBOUNCEMISSILE "
67 "DP_QC_ASINACOSATANATAN2TAN "
73 "DP_QC_CVAR_DEFSTRING "
74 "DP_QC_CVAR_DESCRIPTION "
81 "DP_QC_EXTRESPONSEPACKET "
83 "DP_QC_FINDCHAINFLAGS "
84 "DP_QC_FINDCHAINFLOAT "
85 "DP_QC_FINDCHAIN_TOFIELD "
91 "DP_QC_GETSURFACEPOINTATTRIBUTE "
93 "DP_QC_GETTAGINFO_BONEPROPERTIES "
95 "DP_QC_GETTIME_CDTRACK "
98 "DP_QC_MULTIPLETEMPSTRINGS "
99 "DP_QC_NUM_FOR_EDICT "
101 "DP_QC_SINCOSSQRTPOW "
103 "DP_QC_STRINGBUFFERS "
104 "DP_QC_STRINGBUFFERS_CVARLIST "
105 "DP_QC_STRINGCOLORFUNCTIONS "
106 "DP_QC_STRING_CASE_FUNCTIONS "
108 "DP_QC_TOKENIZEBYSEPARATOR "
109 "DP_QC_TOKENIZE_CONSOLE "
112 "DP_QC_TRACE_MOVETYPE_HITMODEL "
113 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
114 "DP_QC_UNLIMITEDTEMPSTRINGS "
117 "DP_QC_VECTOANGLES_WITH_ROLL "
118 "DP_QC_VECTORVECTORS "
125 "DP_SKELETONOBJECTS "
126 "DP_SND_DIRECTIONLESSATTNNONE "
134 "DP_SV_BOUNCEFACTOR "
135 "DP_SV_CLIENTCOLORS "
138 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
139 "DP_SV_DRAWONLYTOCLIENT "
142 "DP_SV_ENTITYCONTENTSTRANSITION "
143 "DP_SV_MODELFLAGS_AS_EFFECTS "
144 "DP_SV_MOVETYPESTEP_LANDEVENT "
146 "DP_SV_NODRAWTOCLIENT "
147 "DP_SV_ONENTITYNOSPAWNFUNCTION "
148 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
150 "DP_SV_PLAYERPHYSICS "
151 "DP_SV_POINTPARTICLES "
153 "DP_SV_PRECACHEANYTIME "
157 "DP_SV_ROTATINGBMODEL "
161 "DP_SV_SPAWNFUNC_PREFIX "
162 "DP_SV_WRITEPICTURE "
163 "DP_SV_WRITEUNTERMINATEDSTRING "
167 "DP_TE_EXPLOSIONRGB "
169 "DP_TE_PARTICLECUBE "
170 "DP_TE_PARTICLERAIN "
171 "DP_TE_PARTICLESNOW "
173 "DP_TE_QUADEFFECTS1 "
176 "DP_TE_STANDARDEFFECTBUILTINS "
177 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
181 "FTE_CSQC_SKELETONOBJECTS "
184 "KRIMZON_SV_PARSECLIENTCOMMAND "
187 "NEXUIZ_PLAYERMODEL "
189 "PRYDON_CLIENTCURSOR "
190 "TENEBRAE_GFX_DLIGHTS "
193 //"EXT_CSQC " // not ready yet
200 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.
202 setorigin (entity, origin)
205 static void VM_SV_setorigin (void)
210 VM_SAFEPARMCOUNT(2, VM_setorigin);
212 e = PRVM_G_EDICT(OFS_PARM0);
213 if (e == prog->edicts)
215 VM_Warning("setorigin: can not modify world entity\n");
218 if (e->priv.server->free)
220 VM_Warning("setorigin: can not modify free entity\n");
223 org = PRVM_G_VECTOR(OFS_PARM1);
224 VectorCopy (org, e->fields.server->origin);
228 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
229 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
233 for (i=0 ; i<3 ; i++)
235 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
237 // set derived values
238 VectorCopy (min, e->fields.server->mins);
239 VectorCopy (max, e->fields.server->maxs);
240 VectorSubtract (max, min, e->fields.server->size);
249 the size box is rotated by the current angle
250 LordHavoc: no it isn't...
252 setsize (entity, minvector, maxvector)
255 static void VM_SV_setsize (void)
260 VM_SAFEPARMCOUNT(3, VM_setsize);
262 e = PRVM_G_EDICT(OFS_PARM0);
263 if (e == prog->edicts)
265 VM_Warning("setsize: can not modify world entity\n");
268 if (e->priv.server->free)
270 VM_Warning("setsize: can not modify free entity\n");
273 min = PRVM_G_VECTOR(OFS_PARM1);
274 max = PRVM_G_VECTOR(OFS_PARM2);
275 SetMinMaxSize (e, min, max, false);
283 setmodel(entity, model)
286 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
287 static void VM_SV_setmodel (void)
293 VM_SAFEPARMCOUNT(2, VM_setmodel);
295 e = PRVM_G_EDICT(OFS_PARM0);
296 if (e == prog->edicts)
298 VM_Warning("setmodel: can not modify world entity\n");
301 if (e->priv.server->free)
303 VM_Warning("setmodel: can not modify free entity\n");
306 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
307 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
308 e->fields.server->modelindex = i;
310 mod = SV_GetModelByIndex(i);
314 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
315 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
317 SetMinMaxSize (e, quakemins, quakemaxs, true);
320 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
327 single print to a specific client
329 sprint(clientent, value)
332 static void VM_SV_sprint (void)
336 char string[VM_STRINGTEMP_LENGTH];
338 VM_VarString(1, string, sizeof(string));
340 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
342 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
343 // LordHavoc: div0 requested that sprintto world operate like print
350 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
352 VM_Warning("tried to centerprint to a non-client\n");
356 client = svs.clients + entnum-1;
357 if (!client->netconnection)
360 MSG_WriteChar(&client->netconnection->message,svc_print);
361 MSG_WriteString(&client->netconnection->message, string);
369 single print to a specific client
371 centerprint(clientent, value)
374 static void VM_SV_centerprint (void)
378 char string[VM_STRINGTEMP_LENGTH];
380 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
382 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
384 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
386 VM_Warning("tried to centerprint to a non-client\n");
390 client = svs.clients + entnum-1;
391 if (!client->netconnection)
394 VM_VarString(1, string, sizeof(string));
395 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
396 MSG_WriteString(&client->netconnection->message, string);
403 particle(origin, color, count)
406 static void VM_SV_particle (void)
412 VM_SAFEPARMCOUNT(4, VM_SV_particle);
414 org = PRVM_G_VECTOR(OFS_PARM0);
415 dir = PRVM_G_VECTOR(OFS_PARM1);
416 color = PRVM_G_FLOAT(OFS_PARM2);
417 count = PRVM_G_FLOAT(OFS_PARM3);
418 SV_StartParticle (org, dir, (int)color, (int)count);
428 static void VM_SV_ambientsound (void)
432 float vol, attenuation;
435 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
437 pos = PRVM_G_VECTOR (OFS_PARM0);
438 samp = PRVM_G_STRING(OFS_PARM1);
439 vol = PRVM_G_FLOAT(OFS_PARM2);
440 attenuation = PRVM_G_FLOAT(OFS_PARM3);
442 // check to see if samp was properly precached
443 soundnum = SV_SoundIndex(samp, 1);
451 // add an svc_spawnambient command to the level signon packet
454 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
456 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
458 MSG_WriteVector(&sv.signon, pos, sv.protocol);
460 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
461 MSG_WriteShort (&sv.signon, soundnum);
463 MSG_WriteByte (&sv.signon, soundnum);
465 MSG_WriteByte (&sv.signon, (int)(vol*255));
466 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
474 Each entity can have eight independant sound sources, like voice,
477 Channel 0 is an auto-allocate channel, the others override anything
478 already running on that entity/channel pair.
480 An attenuation of 0 will play full volume everywhere in the level.
481 Larger attenuations will drop off.
485 static void VM_SV_sound (void)
489 prvm_edict_t *entity;
493 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
495 entity = PRVM_G_EDICT(OFS_PARM0);
496 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
497 sample = PRVM_G_STRING(OFS_PARM2);
498 volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
499 attenuation = PRVM_G_FLOAT(OFS_PARM4);
502 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
506 if (volume < 0 || volume > 255)
508 VM_Warning("SV_StartSound: volume must be in range 0-1\n");
512 if (attenuation < 0 || attenuation > 4)
514 VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
518 if (channel < 0 || channel > 7)
520 VM_Warning("SV_StartSound: channel must be in range 0-7\n");
524 SV_StartSound (entity, channel, sample, volume, attenuation);
531 Follows the same logic as VM_SV_sound, except instead of
532 an entity, an origin for the sound is provided, and channel
533 is omitted (since no entity is being tracked).
537 static void VM_SV_pointsound(void)
544 VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
546 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
547 sample = PRVM_G_STRING(OFS_PARM1);
548 volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
549 attenuation = PRVM_G_FLOAT(OFS_PARM3);
551 if (volume < 0 || volume > 255)
553 VM_Warning("SV_StartPointSound: volume must be in range 0-1\n");
557 if (attenuation < 0 || attenuation > 4)
559 VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
563 SV_StartPointSound (org, sample, volume, attenuation);
570 Used for use tracing and shot targeting
571 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
572 if the tryents flag is set.
574 traceline (vector1, vector2, movetype, ignore)
577 static void VM_SV_traceline (void)
584 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
586 prog->xfunction->builtinsprofile += 30;
588 v1 = PRVM_G_VECTOR(OFS_PARM0);
589 v2 = PRVM_G_VECTOR(OFS_PARM1);
590 move = (int)PRVM_G_FLOAT(OFS_PARM2);
591 ent = PRVM_G_EDICT(OFS_PARM3);
593 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]))
594 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));
596 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
598 VM_SetTraceGlobals(&trace);
606 Used for use tracing and shot targeting
607 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
608 if the tryents flag is set.
610 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
613 // LordHavoc: added this for my own use, VERY useful, similar to traceline
614 static void VM_SV_tracebox (void)
616 float *v1, *v2, *m1, *m2;
621 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
623 prog->xfunction->builtinsprofile += 30;
625 v1 = PRVM_G_VECTOR(OFS_PARM0);
626 m1 = PRVM_G_VECTOR(OFS_PARM1);
627 m2 = PRVM_G_VECTOR(OFS_PARM2);
628 v2 = PRVM_G_VECTOR(OFS_PARM3);
629 move = (int)PRVM_G_FLOAT(OFS_PARM4);
630 ent = PRVM_G_EDICT(OFS_PARM5);
632 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]))
633 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));
635 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
637 VM_SetTraceGlobals(&trace);
640 static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
645 vec3_t original_origin;
646 vec3_t original_velocity;
647 vec3_t original_angles;
648 vec3_t original_avelocity;
652 VectorCopy(tossent->fields.server->origin , original_origin );
653 VectorCopy(tossent->fields.server->velocity , original_velocity );
654 VectorCopy(tossent->fields.server->angles , original_angles );
655 VectorCopy(tossent->fields.server->avelocity, original_avelocity);
657 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
658 if (val != NULL && val->_float != 0)
659 gravity = val->_float;
662 gravity *= sv_gravity.value * 0.025;
664 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
666 SV_CheckVelocity (tossent);
667 tossent->fields.server->velocity[2] -= gravity;
668 VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
669 VectorScale (tossent->fields.server->velocity, 0.05, move);
670 VectorAdd (tossent->fields.server->origin, move, end);
671 trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
672 VectorCopy (trace.endpos, tossent->fields.server->origin);
673 tossent->fields.server->velocity[2] -= gravity;
675 if (trace.fraction < 1)
679 VectorCopy(original_origin , tossent->fields.server->origin );
680 VectorCopy(original_velocity , tossent->fields.server->velocity );
681 VectorCopy(original_angles , tossent->fields.server->angles );
682 VectorCopy(original_avelocity, tossent->fields.server->avelocity);
687 static void VM_SV_tracetoss (void)
691 prvm_edict_t *ignore;
693 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
695 prog->xfunction->builtinsprofile += 600;
697 ent = PRVM_G_EDICT(OFS_PARM0);
698 if (ent == prog->edicts)
700 VM_Warning("tracetoss: can not use world entity\n");
703 ignore = PRVM_G_EDICT(OFS_PARM1);
705 trace = SV_Trace_Toss (ent, ignore);
707 VM_SetTraceGlobals(&trace);
710 //============================================================================
712 static int checkpvsbytes;
713 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
715 static int VM_SV_newcheckclient (int check)
721 // cycle to the next one
723 check = bound(1, check, svs.maxclients);
724 if (check == svs.maxclients)
732 prog->xfunction->builtinsprofile++;
734 if (i == svs.maxclients+1)
736 // look up the client's edict
737 ent = PRVM_EDICT_NUM(i);
738 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
739 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
741 // found a valid client (possibly the same one again)
745 // get the PVS for the entity
746 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
748 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
749 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
758 Returns a client (or object that has a client enemy) that would be a
761 If there is more than one valid option, they are cycled each frame
763 If (self.origin + self.viewofs) is not in the PVS of the current target,
764 it is not returned at all.
769 int c_invis, c_notvis;
770 static void VM_SV_checkclient (void)
772 prvm_edict_t *ent, *self;
775 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
777 // find a new check if on a new frame
778 if (sv.time - sv.lastchecktime >= 0.1)
780 sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
781 sv.lastchecktime = sv.time;
784 // return check if it might be visible
785 ent = PRVM_EDICT_NUM(sv.lastcheck);
786 if (ent->priv.server->free || ent->fields.server->health <= 0)
788 VM_RETURN_EDICT(prog->edicts);
792 // if current entity can't possibly see the check entity, return 0
793 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
794 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
795 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
798 VM_RETURN_EDICT(prog->edicts);
802 // might be able to see it
804 VM_RETURN_EDICT(ent);
807 //============================================================================
813 Checks if an entity is in a point's PVS.
814 Should be fast but can be inexact.
816 float checkpvs(vector viewpos, entity viewee) = #240;
819 static void VM_SV_checkpvs (void)
822 prvm_edict_t *viewee;
827 unsigned char fatpvs[MAX_MAP_LEAFS/8];
830 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
831 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
832 viewee = PRVM_G_EDICT(OFS_PARM1);
834 if(viewee->priv.server->free)
836 VM_Warning("checkpvs: can not check free entity\n");
837 PRVM_G_FLOAT(OFS_RETURN) = 4;
842 if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
844 // no PVS support on this worldmodel... darn
845 PRVM_G_FLOAT(OFS_RETURN) = 3;
848 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
851 // viewpos isn't in any PVS... darn
852 PRVM_G_FLOAT(OFS_RETURN) = 2;
855 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
857 // using fat PVS like FTEQW does (slow)
858 if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
860 // no PVS support on this worldmodel... darn
861 PRVM_G_FLOAT(OFS_RETURN) = 3;
864 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
867 // viewpos isn't in any PVS... darn
868 PRVM_G_FLOAT(OFS_RETURN) = 2;
871 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
880 Sends text over to the client's execution buffer
882 stuffcmd (clientent, value, ...)
885 static void VM_SV_stuffcmd (void)
889 char string[VM_STRINGTEMP_LENGTH];
891 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
893 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
894 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
896 VM_Warning("Can't stuffcmd to a non-client\n");
900 VM_VarString(1, string, sizeof(string));
903 host_client = svs.clients + entnum-1;
904 Host_ClientCommands ("%s", string);
912 Returns a chain of entities that have origins within a spherical area
914 findradius (origin, radius)
917 static void VM_SV_findradius (void)
919 prvm_edict_t *ent, *chain;
920 vec_t radius, radius2;
921 vec3_t org, eorg, mins, maxs;
924 prvm_edict_t *touchedicts[MAX_EDICTS];
927 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
930 chainfield = PRVM_G_INT(OFS_PARM2);
932 chainfield = prog->fieldoffsets.chain;
934 PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
936 chain = (prvm_edict_t *)prog->edicts;
938 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
939 radius = PRVM_G_FLOAT(OFS_PARM1);
940 radius2 = radius * radius;
942 mins[0] = org[0] - (radius + 1);
943 mins[1] = org[1] - (radius + 1);
944 mins[2] = org[2] - (radius + 1);
945 maxs[0] = org[0] + (radius + 1);
946 maxs[1] = org[1] + (radius + 1);
947 maxs[2] = org[2] + (radius + 1);
948 numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
949 if (numtouchedicts > MAX_EDICTS)
951 // this never happens
952 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
953 numtouchedicts = MAX_EDICTS;
955 for (i = 0;i < numtouchedicts;i++)
957 ent = touchedicts[i];
958 prog->xfunction->builtinsprofile++;
959 // Quake did not return non-solid entities but darkplaces does
960 // (note: this is the reason you can't blow up fallen zombies)
961 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
963 // LordHavoc: compare against bounding box rather than center so it
964 // doesn't miss large objects, and use DotProduct instead of Length
965 // for a major speedup
966 VectorSubtract(org, ent->fields.server->origin, eorg);
967 if (sv_gameplayfix_findradiusdistancetobox.integer)
969 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
970 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
971 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
974 VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
975 if (DotProduct(eorg, eorg) < radius2)
977 PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
982 VM_RETURN_EDICT(chain);
985 static void VM_SV_precache_sound (void)
987 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
988 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
991 static void VM_SV_precache_model (void)
993 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
994 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
995 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1002 float(float yaw, float dist[, settrace]) walkmove
1005 static void VM_SV_walkmove (void)
1014 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1016 // assume failure if it returns early
1017 PRVM_G_FLOAT(OFS_RETURN) = 0;
1019 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1020 if (ent == prog->edicts)
1022 VM_Warning("walkmove: can not modify world entity\n");
1025 if (ent->priv.server->free)
1027 VM_Warning("walkmove: can not modify free entity\n");
1030 yaw = PRVM_G_FLOAT(OFS_PARM0);
1031 dist = PRVM_G_FLOAT(OFS_PARM1);
1032 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1034 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1037 yaw = yaw*M_PI*2 / 360;
1039 move[0] = cos(yaw)*dist;
1040 move[1] = sin(yaw)*dist;
1043 // save program state, because SV_movestep may call other progs
1044 oldf = prog->xfunction;
1045 oldself = prog->globals.server->self;
1047 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1050 // restore program state
1051 prog->xfunction = oldf;
1052 prog->globals.server->self = oldself;
1062 static void VM_SV_droptofloor (void)
1068 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1070 // assume failure if it returns early
1071 PRVM_G_FLOAT(OFS_RETURN) = 0;
1073 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1074 if (ent == prog->edicts)
1076 VM_Warning("droptofloor: can not modify world entity\n");
1079 if (ent->priv.server->free)
1081 VM_Warning("droptofloor: can not modify free entity\n");
1085 VectorCopy (ent->fields.server->origin, end);
1088 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1089 SV_UnstickEntity(ent);
1091 trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1092 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1095 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]);
1096 VectorAdd(ent->fields.server->origin, offset, org);
1097 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1098 VectorSubtract(trace.endpos, offset, trace.endpos);
1099 if (trace.startsolid)
1101 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]);
1102 SV_UnstickEntity(ent);
1104 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1105 ent->fields.server->groundentity = 0;
1106 PRVM_G_FLOAT(OFS_RETURN) = 1;
1108 else if (trace.fraction < 1)
1110 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]);
1111 VectorCopy (trace.endpos, ent->fields.server->origin);
1112 SV_UnstickEntity(ent);
1114 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1115 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1116 PRVM_G_FLOAT(OFS_RETURN) = 1;
1117 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1118 ent->priv.server->suspendedinairflag = true;
1123 if (trace.fraction != 1)
1125 if (trace.fraction < 1)
1126 VectorCopy (trace.endpos, ent->fields.server->origin);
1128 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1129 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1130 PRVM_G_FLOAT(OFS_RETURN) = 1;
1131 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1132 ent->priv.server->suspendedinairflag = true;
1141 void(float style, string value) lightstyle
1144 static void VM_SV_lightstyle (void)
1151 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1153 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1154 val = PRVM_G_STRING(OFS_PARM1);
1156 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1157 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
1160 // change the string in sv
1161 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1163 // send message to all clients on this server
1164 if (sv.state != ss_active)
1167 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1169 if (client->active && client->netconnection)
1171 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1172 MSG_WriteChar (&client->netconnection->message,style);
1173 MSG_WriteString (&client->netconnection->message, val);
1183 static void VM_SV_checkbottom (void)
1185 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1186 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1194 static void VM_SV_pointcontents (void)
1196 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1197 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1204 Pick a vector for the player to shoot along
1205 vector aim(entity, missilespeed)
1208 static void VM_SV_aim (void)
1210 prvm_edict_t *ent, *check, *bestent;
1211 vec3_t start, dir, end, bestdir;
1214 float dist, bestdist;
1217 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1219 // assume failure if it returns early
1220 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1221 // if sv_aim is so high it can't possibly accept anything, skip out early
1222 if (sv_aim.value >= 1)
1225 ent = PRVM_G_EDICT(OFS_PARM0);
1226 if (ent == prog->edicts)
1228 VM_Warning("aim: can not use world entity\n");
1231 if (ent->priv.server->free)
1233 VM_Warning("aim: can not use free entity\n");
1236 speed = PRVM_G_FLOAT(OFS_PARM1);
1238 VectorCopy (ent->fields.server->origin, start);
1241 // try sending a trace straight
1242 VectorCopy (prog->globals.server->v_forward, dir);
1243 VectorMA (start, 2048, dir, end);
1244 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1245 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1246 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1248 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1253 // try all possible entities
1254 VectorCopy (dir, bestdir);
1255 bestdist = sv_aim.value;
1258 check = PRVM_NEXT_EDICT(prog->edicts);
1259 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1261 prog->xfunction->builtinsprofile++;
1262 if (check->fields.server->takedamage != DAMAGE_AIM)
1266 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1267 continue; // don't aim at teammate
1268 for (j=0 ; j<3 ; j++)
1269 end[j] = check->fields.server->origin[j]
1270 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1271 VectorSubtract (end, start, dir);
1272 VectorNormalize (dir);
1273 dist = DotProduct (dir, prog->globals.server->v_forward);
1274 if (dist < bestdist)
1275 continue; // to far to turn
1276 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1277 if (tr.ent == check)
1278 { // can shoot at this one
1286 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1287 dist = DotProduct (dir, prog->globals.server->v_forward);
1288 VectorScale (prog->globals.server->v_forward, dist, end);
1290 VectorNormalize (end);
1291 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1295 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1300 ===============================================================================
1304 ===============================================================================
1307 #define MSG_BROADCAST 0 // unreliable to all
1308 #define MSG_ONE 1 // reliable to one (msg_entity)
1309 #define MSG_ALL 2 // reliable to all
1310 #define MSG_INIT 3 // write to the init string
1311 #define MSG_ENTITY 5
1313 sizebuf_t *WriteDest (void)
1319 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1323 return &sv.datagram;
1326 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1327 entnum = PRVM_NUM_FOR_EDICT(ent);
1328 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1330 VM_Warning ("WriteDest: tried to write to non-client\n");
1331 return &sv.reliable_datagram;
1334 return &svs.clients[entnum-1].netconnection->message;
1337 VM_Warning ("WriteDest: bad destination\n");
1339 return &sv.reliable_datagram;
1345 return sv.writeentitiestoclient_msg;
1351 static void VM_SV_WriteByte (void)
1353 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1354 MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1357 static void VM_SV_WriteChar (void)
1359 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1360 MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1363 static void VM_SV_WriteShort (void)
1365 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1366 MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1369 static void VM_SV_WriteLong (void)
1371 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1372 MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1375 static void VM_SV_WriteAngle (void)
1377 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1378 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1381 static void VM_SV_WriteCoord (void)
1383 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1384 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1387 static void VM_SV_WriteString (void)
1389 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1390 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1393 static void VM_SV_WriteUnterminatedString (void)
1395 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1396 MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1400 static void VM_SV_WriteEntity (void)
1402 VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
1403 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1406 // writes a picture as at most size bytes of data
1408 // IMGNAME \0 SIZE(short) IMGDATA
1409 // if failed to read/compress:
1411 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1412 static void VM_SV_WritePicture (void)
1414 const char *imgname;
1418 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1420 imgname = PRVM_G_STRING(OFS_PARM1);
1421 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1425 MSG_WriteString(WriteDest(), imgname);
1426 if(Image_Compress(imgname, size, &buf, &size))
1429 MSG_WriteShort(WriteDest(), size);
1430 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1435 MSG_WriteShort(WriteDest(), 0);
1439 //////////////////////////////////////////////////////////
1441 static void VM_SV_makestatic (void)
1446 // allow 0 parameters due to an id1 qc bug in which this function is used
1447 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1448 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1450 if (prog->argc >= 1)
1451 ent = PRVM_G_EDICT(OFS_PARM0);
1453 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1454 if (ent == prog->edicts)
1456 VM_Warning("makestatic: can not modify world entity\n");
1459 if (ent->priv.server->free)
1461 VM_Warning("makestatic: can not modify free entity\n");
1466 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1471 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1472 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1473 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1475 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1477 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1478 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1479 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1483 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1484 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1485 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1488 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1489 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1490 for (i=0 ; i<3 ; i++)
1492 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1493 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1496 // throw the entity away now
1500 //=============================================================================
1507 static void VM_SV_setspawnparms (void)
1513 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1515 ent = PRVM_G_EDICT(OFS_PARM0);
1516 i = PRVM_NUM_FOR_EDICT(ent);
1517 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1519 Con_Print("tried to setspawnparms on a non-client\n");
1523 // copy spawn parms out of the client_t
1524 client = svs.clients + i-1;
1525 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1526 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1533 Returns a color vector indicating the lighting at the requested point.
1535 (Internal Operation note: actually measures the light beneath the point, just like
1536 the model lighting on the client)
1541 static void VM_SV_getlight (void)
1543 vec3_t ambientcolor, diffusecolor, diffusenormal;
1545 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1546 p = PRVM_G_VECTOR(OFS_PARM0);
1547 VectorClear(ambientcolor);
1548 VectorClear(diffusecolor);
1549 VectorClear(diffusenormal);
1550 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1551 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1552 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1557 unsigned char type; // 1/2/8 or other value if isn't used
1561 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1562 static int vm_customstats_last;
1564 void VM_CustomStats_Clear (void)
1568 Z_Free(vm_customstats);
1569 vm_customstats = NULL;
1570 vm_customstats_last = -1;
1574 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1582 for(i=0; i<vm_customstats_last+1 ;i++)
1584 if(!vm_customstats[i].type)
1586 switch(vm_customstats[i].type)
1588 //string as 16 bytes
1591 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1592 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1593 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1594 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1595 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1597 //float field sent as-is
1599 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1601 //integer value of float field
1603 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1611 // void(float index, float type, .void field) SV_AddStat = #232;
1612 // Set up an auto-sent player stat.
1613 // Client's get thier own fields sent to them. Index may not be less than 32.
1614 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1615 // 1: string (4 stats carrying a total of 16 charactures)
1616 // 2: float (one stat, float converted to an integer for transportation)
1617 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1618 static void VM_SV_AddStat (void)
1623 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1627 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1630 VM_Warning("PF_SV_AddStat: not enough memory\n");
1634 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1635 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1636 off = PRVM_G_INT (OFS_PARM2);
1641 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1644 if(i >= (MAX_CL_STATS-32))
1646 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1649 if(i > (MAX_CL_STATS-32-4) && type == 1)
1651 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1654 vm_customstats[i].type = type;
1655 vm_customstats[i].fieldoffset = off;
1656 if(vm_customstats_last < i)
1657 vm_customstats_last = i;
1664 copies data from one entity to another
1666 copyentity(src, dst)
1669 static void VM_SV_copyentity (void)
1671 prvm_edict_t *in, *out;
1672 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1673 in = PRVM_G_EDICT(OFS_PARM0);
1674 if (in == prog->edicts)
1676 VM_Warning("copyentity: can not read world entity\n");
1679 if (in->priv.server->free)
1681 VM_Warning("copyentity: can not read free entity\n");
1684 out = PRVM_G_EDICT(OFS_PARM1);
1685 if (out == prog->edicts)
1687 VM_Warning("copyentity: can not modify world entity\n");
1690 if (out->priv.server->free)
1692 VM_Warning("copyentity: can not modify free entity\n");
1695 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1704 sets the color of a client and broadcasts the update to all connected clients
1706 setcolor(clientent, value)
1709 static void VM_SV_setcolor (void)
1715 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1716 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1717 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1719 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1721 Con_Print("tried to setcolor a non-client\n");
1725 client = svs.clients + entnum-1;
1728 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1730 client->edict->fields.server->team = (i & 15) + 1;
1733 if (client->old_colors != client->colors)
1735 client->old_colors = client->colors;
1736 // send notification to all clients
1737 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1738 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1739 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1747 effect(origin, modelname, startframe, framecount, framerate)
1750 static void VM_SV_effect (void)
1754 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1755 s = PRVM_G_STRING(OFS_PARM1);
1758 VM_Warning("effect: no model specified\n");
1762 i = SV_ModelIndex(s, 1);
1765 VM_Warning("effect: model not precached\n");
1769 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1771 VM_Warning("effect: framecount < 1\n");
1775 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1777 VM_Warning("effect: framerate < 1\n");
1781 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));
1784 static void VM_SV_te_blood (void)
1786 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1787 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1789 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1790 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1792 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1793 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1794 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1796 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1797 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1798 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1800 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1801 SV_FlushBroadcastMessages();
1804 static void VM_SV_te_bloodshower (void)
1806 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1807 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1809 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1810 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1812 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1813 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1814 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1816 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1817 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1818 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1820 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1822 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1823 SV_FlushBroadcastMessages();
1826 static void VM_SV_te_explosionrgb (void)
1828 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1829 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1830 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1832 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1833 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1834 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1836 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1837 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1838 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1839 SV_FlushBroadcastMessages();
1842 static void VM_SV_te_particlecube (void)
1844 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1845 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1847 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1848 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1850 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1851 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1852 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1854 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1855 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1856 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1858 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1859 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1860 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1862 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1864 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1865 // gravity true/false
1866 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1868 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1869 SV_FlushBroadcastMessages();
1872 static void VM_SV_te_particlerain (void)
1874 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1875 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1877 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1878 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1880 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1881 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1882 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1885 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1886 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1888 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1889 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1890 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1892 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1894 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1895 SV_FlushBroadcastMessages();
1898 static void VM_SV_te_particlesnow (void)
1900 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1901 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1903 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1904 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1906 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1908 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1912 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1914 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1915 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1916 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1918 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1920 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1921 SV_FlushBroadcastMessages();
1924 static void VM_SV_te_spark (void)
1926 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1927 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1929 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1930 MSG_WriteByte(&sv.datagram, TE_SPARK);
1932 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1933 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1934 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1936 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1937 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1938 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1940 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1941 SV_FlushBroadcastMessages();
1944 static void VM_SV_te_gunshotquad (void)
1946 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1947 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1948 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1950 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1951 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1952 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1953 SV_FlushBroadcastMessages();
1956 static void VM_SV_te_spikequad (void)
1958 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
1959 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1960 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1962 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1963 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1964 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1965 SV_FlushBroadcastMessages();
1968 static void VM_SV_te_superspikequad (void)
1970 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
1971 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1972 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1974 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1976 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1977 SV_FlushBroadcastMessages();
1980 static void VM_SV_te_explosionquad (void)
1982 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
1983 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1984 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1986 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1987 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1988 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1989 SV_FlushBroadcastMessages();
1992 static void VM_SV_te_smallflash (void)
1994 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
1995 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1996 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1998 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1999 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2000 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2001 SV_FlushBroadcastMessages();
2004 static void VM_SV_te_customflash (void)
2006 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2007 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2009 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2010 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2012 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2013 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2014 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2016 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2018 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2020 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2021 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2022 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2023 SV_FlushBroadcastMessages();
2026 static void VM_SV_te_gunshot (void)
2028 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2029 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2030 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2032 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2033 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2034 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2035 SV_FlushBroadcastMessages();
2038 static void VM_SV_te_spike (void)
2040 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2041 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2042 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2044 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2045 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2046 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2047 SV_FlushBroadcastMessages();
2050 static void VM_SV_te_superspike (void)
2052 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2053 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2054 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2056 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2057 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2058 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2059 SV_FlushBroadcastMessages();
2062 static void VM_SV_te_explosion (void)
2064 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2065 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2066 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2068 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2069 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2070 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2071 SV_FlushBroadcastMessages();
2074 static void VM_SV_te_tarexplosion (void)
2076 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2077 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2078 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2080 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2081 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2082 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2083 SV_FlushBroadcastMessages();
2086 static void VM_SV_te_wizspike (void)
2088 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2089 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2090 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2092 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2093 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2094 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2095 SV_FlushBroadcastMessages();
2098 static void VM_SV_te_knightspike (void)
2100 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2101 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2102 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2104 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2105 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2106 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2107 SV_FlushBroadcastMessages();
2110 static void VM_SV_te_lavasplash (void)
2112 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2113 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2114 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2116 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2117 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2118 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2119 SV_FlushBroadcastMessages();
2122 static void VM_SV_te_teleport (void)
2124 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2125 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2126 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2128 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2129 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2130 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2131 SV_FlushBroadcastMessages();
2134 static void VM_SV_te_explosion2 (void)
2136 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2137 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2138 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2140 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2141 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2142 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2144 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2145 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2146 SV_FlushBroadcastMessages();
2149 static void VM_SV_te_lightning1 (void)
2151 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2152 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2153 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2155 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2157 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2158 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2159 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2161 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2162 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2163 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2164 SV_FlushBroadcastMessages();
2167 static void VM_SV_te_lightning2 (void)
2169 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2170 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2171 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2173 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2175 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2176 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2177 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2179 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2180 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2181 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2182 SV_FlushBroadcastMessages();
2185 static void VM_SV_te_lightning3 (void)
2187 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2188 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2189 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2191 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2193 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2194 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2195 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2197 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2198 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2199 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2200 SV_FlushBroadcastMessages();
2203 static void VM_SV_te_beam (void)
2205 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2206 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2207 MSG_WriteByte(&sv.datagram, TE_BEAM);
2209 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2211 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2212 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2213 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2215 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2216 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2217 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2218 SV_FlushBroadcastMessages();
2221 static void VM_SV_te_plasmaburn (void)
2223 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2224 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2225 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2226 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2227 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2228 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2229 SV_FlushBroadcastMessages();
2232 static void VM_SV_te_flamejet (void)
2234 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2235 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2236 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2238 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2239 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2240 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2244 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2246 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2247 SV_FlushBroadcastMessages();
2250 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2253 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2255 bestdist = 1000000000;
2257 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2259 // clip original point to each triangle of the surface and find the
2260 // triangle that is closest
2261 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2262 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2263 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2264 TriangleNormal(v[0], v[1], v[2], facenormal);
2265 VectorNormalize(facenormal);
2266 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2267 VectorMA(p, offsetdist, facenormal, temp);
2268 for (j = 0, k = 2;j < 3;k = j, j++)
2270 VectorSubtract(v[k], v[j], edgenormal);
2271 CrossProduct(edgenormal, facenormal, sidenormal);
2272 VectorNormalize(sidenormal);
2273 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2275 VectorMA(temp, offsetdist, sidenormal, temp);
2277 dist = VectorDistance2(temp, p);
2278 if (bestdist > dist)
2281 VectorCopy(temp, out);
2286 #define getmodel SV_GetModelFromEdict
2288 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2290 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2292 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2296 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2297 static void VM_SV_getsurfacenumpoints(void)
2300 msurface_t *surface;
2301 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2302 // return 0 if no such surface
2303 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2305 PRVM_G_FLOAT(OFS_RETURN) = 0;
2309 // note: this (incorrectly) assumes it is a simple polygon
2310 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2312 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2313 static void VM_SV_getsurfacepoint(void)
2317 msurface_t *surface;
2319 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2320 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2321 ed = PRVM_G_EDICT(OFS_PARM0);
2322 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2324 // note: this (incorrectly) assumes it is a simple polygon
2325 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2326 if (pointnum < 0 || pointnum >= surface->num_vertices)
2328 // FIXME: implement rotation/scaling
2329 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2331 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2332 // float SPA_POSITION = 0;
2333 // float SPA_S_AXIS = 1;
2334 // float SPA_T_AXIS = 2;
2335 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2336 // float SPA_TEXCOORDS0 = 4;
2337 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2338 // float SPA_LIGHTMAP0_COLOR = 6;
2339 static void VM_SV_getsurfacepointattribute(void)
2343 msurface_t *surface;
2347 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2348 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2349 ed = PRVM_G_EDICT(OFS_PARM0);
2350 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2352 // note: this (incorrectly) assumes it is a simple polygon
2353 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2354 if (pointnum < 0 || pointnum >= surface->num_vertices)
2356 // FIXME: implement rotation/scaling
2357 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2359 switch( attributetype ) {
2360 // float SPA_POSITION = 0;
2362 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2364 // float SPA_S_AXIS = 1;
2366 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2368 // float SPA_T_AXIS = 2;
2370 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2372 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2374 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2376 // float SPA_TEXCOORDS0 = 4;
2378 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2379 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2380 ret[0] = texcoord[0];
2381 ret[1] = texcoord[1];
2385 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2387 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2388 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2389 ret[0] = texcoord[0];
2390 ret[1] = texcoord[1];
2394 // float SPA_LIGHTMAP0_COLOR = 6;
2396 // ignore alpha for now..
2397 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2400 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2404 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2405 static void VM_SV_getsurfacenormal(void)
2408 msurface_t *surface;
2410 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2411 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2412 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2414 // FIXME: implement rotation/scaling
2415 // note: this (incorrectly) assumes it is a simple polygon
2416 // note: this only returns the first triangle, so it doesn't work very
2417 // well for curved surfaces or arbitrary meshes
2418 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);
2419 VectorNormalize(normal);
2420 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2422 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2423 static void VM_SV_getsurfacetexture(void)
2426 msurface_t *surface;
2427 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2428 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2429 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2431 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2433 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2434 static void VM_SV_getsurfacenearpoint(void)
2436 int surfacenum, best;
2438 vec_t dist, bestdist;
2441 msurface_t *surface;
2443 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2444 PRVM_G_FLOAT(OFS_RETURN) = -1;
2445 ed = PRVM_G_EDICT(OFS_PARM0);
2446 point = PRVM_G_VECTOR(OFS_PARM1);
2448 if (!ed || ed->priv.server->free)
2450 model = getmodel(ed);
2451 if (!model || !model->num_surfaces)
2454 // FIXME: implement rotation/scaling
2455 VectorSubtract(point, ed->fields.server->origin, p);
2457 bestdist = 1000000000;
2458 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2460 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2461 // first see if the nearest point on the surface's box is closer than the previous match
2462 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2463 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2464 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2465 dist = VectorLength2(clipped);
2466 if (dist < bestdist)
2468 // it is, check the nearest point on the actual geometry
2469 clippointtosurface(model, surface, p, clipped);
2470 VectorSubtract(clipped, p, clipped);
2471 dist += VectorLength2(clipped);
2472 if (dist < bestdist)
2474 // that's closer too, store it as the best match
2480 PRVM_G_FLOAT(OFS_RETURN) = best;
2482 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2483 static void VM_SV_getsurfaceclippedpoint(void)
2487 msurface_t *surface;
2489 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2490 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2491 ed = PRVM_G_EDICT(OFS_PARM0);
2492 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2494 // FIXME: implement rotation/scaling
2495 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2496 clippointtosurface(model, surface, p, out);
2497 // FIXME: implement rotation/scaling
2498 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2501 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2502 //this function originally written by KrimZon, made shorter by LordHavoc
2503 static void VM_SV_clientcommand (void)
2505 client_t *temp_client;
2507 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2509 //find client for this entity
2510 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2511 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2513 Con_Print("PF_clientcommand: entity is not a client\n");
2517 temp_client = host_client;
2518 host_client = svs.clients + i;
2519 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2520 host_client = temp_client;
2523 //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)
2524 static void VM_SV_setattachment (void)
2526 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2527 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2528 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2531 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2533 if (e == prog->edicts)
2535 VM_Warning("setattachment: can not modify world entity\n");
2538 if (e->priv.server->free)
2540 VM_Warning("setattachment: can not modify free entity\n");
2544 if (tagentity == NULL)
2545 tagentity = prog->edicts;
2547 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2549 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2551 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2554 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2556 model = SV_GetModelFromEdict(tagentity);
2559 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2561 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);
2564 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));
2568 /////////////////////////////////////////
2569 // DP_MD3_TAGINFO extension coded by VorteX
2571 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2575 i = (int)e->fields.server->modelindex;
2576 if (i < 1 || i >= MAX_MODELS)
2579 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2582 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2589 Matrix4x4_CreateIdentity(tag_localmatrix);
2591 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2593 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2604 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2608 float pitchsign = 1;
2611 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2612 if (val && val->_float != 0)
2613 scale = val->_float;
2616 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);
2619 pitchsign = SV_GetPitchSign(ent);
2620 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);
2624 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2627 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->num_bones)
2629 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2630 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2631 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2632 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2634 *out = identitymatrix;
2638 // Warnings/errors code:
2639 // 0 - normal (everything all-right)
2642 // 3 - null or non-precached model
2643 // 4 - no tags with requested index
2644 // 5 - runaway loop at attachment chain
2645 extern cvar_t cl_bob;
2646 extern cvar_t cl_bobcycle;
2647 extern cvar_t cl_bobup;
2648 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2652 int modelindex, attachloop;
2653 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2656 *out = identitymatrix; // warnings and errors return identical matrix
2658 if (ent == prog->edicts)
2660 if (ent->priv.server->free)
2663 modelindex = (int)ent->fields.server->modelindex;
2664 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2667 model = SV_GetModelByIndex(modelindex);
2669 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2670 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2671 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2673 tagmatrix = identitymatrix;
2674 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2678 if (attachloop >= 256) // prevent runaway looping
2680 // apply transformation by child's tagindex on parent entity and then
2681 // by parent entity itself
2682 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2683 if (ret && attachloop == 0)
2685 SV_GetEntityMatrix(ent, &entitymatrix, false);
2686 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2687 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2688 // next iteration we process the parent entity
2689 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2691 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2692 ent = PRVM_EDICT_NUM(val->edict);
2699 // RENDER_VIEWMODEL magic
2700 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2702 Matrix4x4_Copy(&tagmatrix, out);
2703 ent = PRVM_EDICT_NUM(val->edict);
2705 SV_GetEntityMatrix(ent, &entitymatrix, true);
2706 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2709 // Cl_bob, ported from rendering code
2710 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2713 // LordHavoc: this code is *weird*, but not replacable (I think it
2714 // should be done in QC on the server, but oh well, quake is quake)
2715 // LordHavoc: figured out bobup: the time at which the sin is at 180
2716 // degrees (which allows lengthening or squishing the peak or valley)
2717 cycle = sv.time/cl_bobcycle.value;
2718 cycle -= (int)cycle;
2719 if (cycle < cl_bobup.value)
2720 cycle = sin(M_PI * cycle / cl_bobup.value);
2722 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2723 // bob is proportional to velocity in the xy plane
2724 // (don't count Z, or jumping messes it up)
2725 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;
2726 bob = bob*0.3 + bob*0.7*cycle;
2727 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2734 //float(entity ent, string tagname) gettagindex;
2736 static void VM_SV_gettagindex (void)
2739 const char *tag_name;
2742 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2744 ent = PRVM_G_EDICT(OFS_PARM0);
2745 tag_name = PRVM_G_STRING(OFS_PARM1);
2747 if (ent == prog->edicts)
2749 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2752 if (ent->priv.server->free)
2754 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2759 if (!SV_GetModelFromEdict(ent))
2760 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2763 tag_index = SV_GetTagIndex(ent, tag_name);
2765 if(developer.integer >= 100)
2766 Con_Printf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2768 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2771 //vector(entity ent, float tagindex) gettaginfo;
2772 static void VM_SV_gettaginfo (void)
2776 matrix4x4_t tag_matrix;
2777 matrix4x4_t tag_localmatrix;
2779 const char *tagname;
2782 vec3_t fo, le, up, trans;
2783 const dp_model_t *model;
2785 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2787 e = PRVM_G_EDICT(OFS_PARM0);
2788 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2790 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2791 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2792 VectorScale(le, -1, prog->globals.server->v_right);
2793 model = SV_GetModelFromEdict(e);
2794 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2795 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2796 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2797 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2798 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2800 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2801 val->_float = parentindex;
2802 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2803 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2804 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2805 VectorCopy(trans, val->vector);
2806 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2807 VectorCopy(fo, val->vector);
2808 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2809 VectorScale(le, -1, val->vector);
2810 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2811 VectorCopy(up, val->vector);
2816 VM_Warning("gettagindex: can't affect world entity\n");
2819 VM_Warning("gettagindex: can't affect free entity\n");
2822 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2825 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2828 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2833 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2834 static void VM_SV_dropclient (void)
2837 client_t *oldhostclient;
2838 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2839 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2840 if (clientnum < 0 || clientnum >= svs.maxclients)
2842 VM_Warning("dropclient: not a client\n");
2845 if (!svs.clients[clientnum].active)
2847 VM_Warning("dropclient: that client slot is not connected\n");
2850 oldhostclient = host_client;
2851 host_client = svs.clients + clientnum;
2852 SV_DropClient(false);
2853 host_client = oldhostclient;
2856 //entity() spawnclient (DP_SV_BOTCLIENT)
2857 static void VM_SV_spawnclient (void)
2861 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2862 prog->xfunction->builtinsprofile += 2;
2864 for (i = 0;i < svs.maxclients;i++)
2866 if (!svs.clients[i].active)
2868 prog->xfunction->builtinsprofile += 100;
2869 SV_ConnectClient (i, NULL);
2870 // this has to be set or else ClientDisconnect won't be called
2871 // we assume the qc will call ClientConnect...
2872 svs.clients[i].clientconnectcalled = true;
2873 ed = PRVM_EDICT_NUM(i + 1);
2877 VM_RETURN_EDICT(ed);
2880 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2881 static void VM_SV_clienttype (void)
2884 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2885 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2886 if (clientnum < 0 || clientnum >= svs.maxclients)
2887 PRVM_G_FLOAT(OFS_RETURN) = 3;
2888 else if (!svs.clients[clientnum].active)
2889 PRVM_G_FLOAT(OFS_RETURN) = 0;
2890 else if (svs.clients[clientnum].netconnection)
2891 PRVM_G_FLOAT(OFS_RETURN) = 1;
2893 PRVM_G_FLOAT(OFS_RETURN) = 2;
2900 string(string key) serverkey
2903 void VM_SV_serverkey(void)
2905 char string[VM_STRINGTEMP_LENGTH];
2906 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2907 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2908 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2911 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2912 static void VM_SV_setmodelindex (void)
2917 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2919 e = PRVM_G_EDICT(OFS_PARM0);
2920 if (e == prog->edicts)
2922 VM_Warning("setmodelindex: can not modify world entity\n");
2925 if (e->priv.server->free)
2927 VM_Warning("setmodelindex: can not modify free entity\n");
2930 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2931 if (i <= 0 || i >= MAX_MODELS)
2933 VM_Warning("setmodelindex: invalid modelindex\n");
2936 if (!sv.model_precache[i][0])
2938 VM_Warning("setmodelindex: model not precached\n");
2942 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2943 e->fields.server->modelindex = i;
2945 mod = SV_GetModelByIndex(i);
2949 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2950 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2952 SetMinMaxSize (e, quakemins, quakemaxs, true);
2955 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
2958 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2959 static void VM_SV_modelnameforindex (void)
2962 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2964 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2966 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2967 if (i <= 0 || i >= MAX_MODELS)
2969 VM_Warning("modelnameforindex: invalid modelindex\n");
2972 if (!sv.model_precache[i][0])
2974 VM_Warning("modelnameforindex: model not precached\n");
2978 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
2981 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2982 static void VM_SV_particleeffectnum (void)
2985 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
2986 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
2989 PRVM_G_FLOAT(OFS_RETURN) = i;
2992 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2993 static void VM_SV_trailparticles (void)
2995 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
2997 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3000 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3001 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3002 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3003 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3004 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3005 SV_FlushBroadcastMessages();
3008 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3009 static void VM_SV_pointparticles (void)
3011 int effectnum, count;
3013 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3015 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3018 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3019 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3020 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3021 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3022 if (count == 1 && !VectorLength2(vel))
3025 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3026 MSG_WriteShort(&sv.datagram, effectnum);
3027 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3031 // 1+2+12+12+2=29 bytes
3032 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3033 MSG_WriteShort(&sv.datagram, effectnum);
3034 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3035 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3036 MSG_WriteShort(&sv.datagram, count);
3039 SV_FlushBroadcastMessages();
3042 //PF_setpause, // void(float pause) setpause = #531;
3043 static void VM_SV_setpause(void) {
3045 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3046 if (pauseValue != 0) { //pause the game
3048 sv.pausedstart = Sys_DoubleTime();
3049 } else { //disable pause, in case it was enabled
3050 if (sv.paused != 0) {
3055 // send notification to all clients
3056 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3057 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3060 // #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.
3061 static void VM_SV_skel_create(void)
3063 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3064 dp_model_t *model = SV_GetModelByIndex(modelindex);
3065 skeleton_t *skeleton;
3067 PRVM_G_FLOAT(OFS_RETURN) = 0;
3068 if (!model || !model->num_bones)
3070 for (i = 0;i < MAX_EDICTS;i++)
3071 if (!prog->skeletons[i])
3073 if (i == MAX_EDICTS)
3075 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3076 skeleton->model = model;
3077 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3078 // initialize to identity matrices
3079 for (i = 0;i < skeleton->model->num_bones;i++)
3080 skeleton->relativetransforms[i] = identitymatrix;
3081 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3084 // #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
3085 static void VM_SV_skel_build(void)
3087 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3088 skeleton_t *skeleton;
3089 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3090 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3091 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3092 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3093 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3094 dp_model_t *model = SV_GetModelByIndex(modelindex);
3099 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3100 frameblend_t frameblend[MAX_FRAMEBLENDS];
3101 matrix4x4_t blendedmatrix;
3103 PRVM_G_FLOAT(OFS_RETURN) = 0;
3104 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3106 firstbone = max(0, firstbone);
3107 lastbone = min(lastbone, model->num_bones - 1);
3108 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3109 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3110 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3111 blendfrac = 1.0f - retainfrac;
3112 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3113 frameblend[numblends].lerp *= blendfrac;
3114 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3116 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3117 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3118 for (blendindex = 0;blendindex < numblends;blendindex++)
3120 Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3121 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3123 skeleton->relativetransforms[bonenum] = blendedmatrix;
3125 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3128 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3129 static void VM_SV_skel_get_numbones(void)
3131 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3132 skeleton_t *skeleton;
3133 PRVM_G_FLOAT(OFS_RETURN) = 0;
3134 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3136 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3139 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3140 static void VM_SV_skel_get_bonename(void)
3142 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3143 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3144 skeleton_t *skeleton;
3145 PRVM_G_INT(OFS_RETURN) = 0;
3146 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3148 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3150 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3153 // #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)
3154 static void VM_SV_skel_get_boneparent(void)
3156 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3157 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3158 skeleton_t *skeleton;
3159 PRVM_G_FLOAT(OFS_RETURN) = 0;
3160 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3162 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3164 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3167 // #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
3168 static void VM_SV_skel_find_bone(void)
3170 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3171 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3172 skeleton_t *skeleton;
3173 PRVM_G_FLOAT(OFS_RETURN) = 0;
3174 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3176 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3179 // #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)
3180 static void VM_SV_skel_get_bonerel(void)
3182 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3183 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3184 skeleton_t *skeleton;
3186 vec3_t forward, left, up, origin;
3187 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3188 VectorClear(prog->globals.client->v_forward);
3189 VectorClear(prog->globals.client->v_right);
3190 VectorClear(prog->globals.client->v_up);
3191 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3193 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3195 matrix = skeleton->relativetransforms[bonenum];
3196 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3197 VectorCopy(forward, prog->globals.client->v_forward);
3198 VectorNegate(left, prog->globals.client->v_right);
3199 VectorCopy(up, prog->globals.client->v_up);
3200 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3203 // #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)
3204 static void VM_SV_skel_get_boneabs(void)
3206 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3207 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3208 skeleton_t *skeleton;
3211 vec3_t forward, left, up, origin;
3212 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3213 VectorClear(prog->globals.client->v_forward);
3214 VectorClear(prog->globals.client->v_right);
3215 VectorClear(prog->globals.client->v_up);
3216 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3218 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3220 matrix = skeleton->relativetransforms[bonenum];
3221 // convert to absolute
3222 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3225 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3227 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3228 VectorCopy(forward, prog->globals.client->v_forward);
3229 VectorNegate(left, prog->globals.client->v_right);
3230 VectorCopy(up, prog->globals.client->v_up);
3231 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3234 // #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)
3235 static void VM_SV_skel_set_bone(void)
3237 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3238 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3239 vec3_t forward, left, up, origin;
3240 skeleton_t *skeleton;
3242 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3244 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3246 VectorCopy(prog->globals.client->v_forward, forward);
3247 VectorNegate(prog->globals.client->v_right, left);
3248 VectorCopy(prog->globals.client->v_up, up);
3249 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3250 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3251 skeleton->relativetransforms[bonenum] = matrix;
3254 // #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)
3255 static void VM_SV_skel_mul_bone(void)
3257 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3258 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3259 vec3_t forward, left, up, origin;
3260 skeleton_t *skeleton;
3263 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3265 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3267 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3268 VectorCopy(prog->globals.client->v_forward, forward);
3269 VectorNegate(prog->globals.client->v_right, left);
3270 VectorCopy(prog->globals.client->v_up, up);
3271 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3272 temp = skeleton->relativetransforms[bonenum];
3273 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3276 // #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)
3277 static void VM_SV_skel_mul_bones(void)
3279 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3280 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3281 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3283 vec3_t forward, left, up, origin;
3284 skeleton_t *skeleton;
3287 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3289 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3290 VectorCopy(prog->globals.client->v_forward, forward);
3291 VectorNegate(prog->globals.client->v_right, left);
3292 VectorCopy(prog->globals.client->v_up, up);
3293 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3294 firstbone = max(0, firstbone);
3295 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3296 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3298 temp = skeleton->relativetransforms[bonenum];
3299 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3303 // #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
3304 static void VM_SV_skel_copybones(void)
3306 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3307 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3308 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3309 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3311 skeleton_t *skeletondst;
3312 skeleton_t *skeletonsrc;
3313 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3315 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3317 firstbone = max(0, firstbone);
3318 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3319 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3320 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3321 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3324 // #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)
3325 static void VM_SV_skel_delete(void)
3327 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3328 skeleton_t *skeleton;
3329 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3332 prog->skeletons[skeletonindex] = NULL;
3335 // #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
3336 static void VM_SV_frameforname(void)
3338 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3339 dp_model_t *model = SV_GetModelByIndex(modelindex);
3340 const char *name = PRVM_G_STRING(OFS_PARM1);
3342 PRVM_G_FLOAT(OFS_RETURN) = -1;
3343 if (!model || !model->animscenes)
3345 for (i = 0;i < model->numframes;i++)
3347 if (!strcasecmp(model->animscenes[i].name, name))
3349 PRVM_G_FLOAT(OFS_RETURN) = i;
3355 // #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.
3356 static void VM_SV_frameduration(void)
3358 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3359 dp_model_t *model = SV_GetModelByIndex(modelindex);
3360 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3361 PRVM_G_FLOAT(OFS_RETURN) = 0;
3362 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3364 if (model->animscenes[framenum].framerate)
3365 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3369 prvm_builtin_t vm_sv_builtins[] = {
3370 NULL, // #0 NULL function (not callable) (QUAKE)
3371 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3372 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3373 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3374 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3375 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3376 VM_break, // #6 void() break (QUAKE)
3377 VM_random, // #7 float() random (QUAKE)
3378 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3379 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3380 VM_error, // #10 void(string e) error (QUAKE)
3381 VM_objerror, // #11 void(string e) objerror (QUAKE)
3382 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3383 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3384 VM_spawn, // #14 entity() spawn (QUAKE)
3385 VM_remove, // #15 void(entity e) remove (QUAKE)
3386 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3387 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3388 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3389 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3390 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3391 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3392 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3393 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3394 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3395 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3396 VM_ftos, // #26 string(float f) ftos (QUAKE)
3397 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3398 VM_coredump, // #28 void() coredump (QUAKE)
3399 VM_traceon, // #29 void() traceon (QUAKE)
3400 VM_traceoff, // #30 void() traceoff (QUAKE)
3401 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3402 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3403 NULL, // #33 (QUAKE)
3404 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3405 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3406 VM_rint, // #36 float(float v) rint (QUAKE)
3407 VM_floor, // #37 float(float v) floor (QUAKE)
3408 VM_ceil, // #38 float(float v) ceil (QUAKE)
3409 NULL, // #39 (QUAKE)
3410 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3411 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3412 NULL, // #42 (QUAKE)
3413 VM_fabs, // #43 float(float f) fabs (QUAKE)
3414 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3415 VM_cvar, // #45 float(string s) cvar (QUAKE)
3416 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3417 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3418 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3419 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3420 NULL, // #50 (QUAKE)
3421 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3422 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3423 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3424 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3425 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3426 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3427 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3428 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3429 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3430 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3431 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3432 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3433 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3434 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3435 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3436 NULL, // #66 (QUAKE)
3437 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3438 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3439 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3440 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3441 NULL, // #71 (QUAKE)
3442 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3443 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3444 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3445 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3446 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3447 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3448 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3449 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3450 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3451 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3452 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3453 NULL, // #83 (QUAKE)
3454 NULL, // #84 (QUAKE)
3455 NULL, // #85 (QUAKE)
3456 NULL, // #86 (QUAKE)
3457 NULL, // #87 (QUAKE)
3458 NULL, // #88 (QUAKE)
3459 NULL, // #89 (QUAKE)
3460 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3461 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3462 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3463 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3464 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3465 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3466 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3467 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3468 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3469 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3470 // FrikaC and Telejano range #100-#199
3481 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3482 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3483 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3484 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3485 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3486 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3487 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3488 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3489 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3490 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3571 // FTEQW range #200-#299
3590 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3593 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3594 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3595 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3596 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3597 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3598 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3599 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3600 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3601 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3602 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3604 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3612 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3635 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.
3636 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
3637 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3638 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3639 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)
3640 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
3641 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)
3642 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)
3643 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)
3644 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)
3645 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)
3646 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
3647 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)
3648 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
3649 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.
3672 // CSQC range #300-#399
3673 NULL, // #300 void() clearscene (EXT_CSQC)
3674 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3675 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3676 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3677 NULL, // #304 void() renderscene (EXT_CSQC)
3678 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3679 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3680 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3681 NULL, // #308 void() R_EndPolygon
3683 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3684 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3688 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3689 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3690 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3691 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3692 NULL, // #319 void(string name) freepic (EXT_CSQC)
3693 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3694 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3695 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3696 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3697 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3698 NULL, // #325 void(void) drawresetcliparea
3703 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3704 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3705 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3706 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3707 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3708 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3709 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3710 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3711 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3712 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3713 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3714 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3715 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3716 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3717 NULL, // #344 vector() getmousepos (EXT_CSQC)
3718 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3719 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3720 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3721 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3722 NULL, // #349 float() isdemo (EXT_CSQC)
3723 VM_isserver, // #350 float() isserver (EXT_CSQC)
3724 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3725 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3726 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3727 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3733 NULL, // #360 float() readbyte (EXT_CSQC)
3734 NULL, // #361 float() readchar (EXT_CSQC)
3735 NULL, // #362 float() readshort (EXT_CSQC)
3736 NULL, // #363 float() readlong (EXT_CSQC)
3737 NULL, // #364 float() readcoord (EXT_CSQC)
3738 NULL, // #365 float() readangle (EXT_CSQC)
3739 NULL, // #366 string() readstring (EXT_CSQC)
3740 NULL, // #367 float() readfloat (EXT_CSQC)
3773 // LordHavoc's range #400-#499
3774 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3775 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3776 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3777 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3778 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3779 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3780 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3781 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3782 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)
3783 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3784 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3785 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3786 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3787 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3788 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3789 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3790 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3791 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3792 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3793 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3794 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3795 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3796 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3797 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3798 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3799 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3800 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3801 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3802 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3803 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3804 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3805 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3806 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3807 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3808 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3809 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3810 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3811 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3812 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3813 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3814 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3815 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3816 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3817 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3818 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3819 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3820 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3821 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3822 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3823 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3824 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3825 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3826 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3827 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3828 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3829 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3830 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3831 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3833 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3834 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3835 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3836 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3837 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3838 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3839 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3840 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3841 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3842 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3843 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3845 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3846 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3847 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3848 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3849 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3850 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3851 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3852 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3853 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3854 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3855 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3856 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3857 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3858 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3859 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3860 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3868 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3869 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3870 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3871 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3872 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3873 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3874 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3875 VM_SV_WritePicture, // #501
3877 VM_whichpack, // #503 string(string) whichpack = #503;
3884 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3885 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3886 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3887 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3888 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3889 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3890 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3891 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3892 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3893 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3903 VM_loadfromdata, // #529
3904 VM_loadfromfile, // #530
3905 VM_SV_setpause, // #531 void(float pause) setpause = #531;
3979 VM_callfunction, // #605
3980 VM_writetofile, // #606
3981 VM_isfunction, // #607
3987 VM_parseentitydata, // #613
3998 VM_SV_getextresponse, // #624 string getextresponse(void)
4002 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4004 void VM_SV_Cmd_Init(void)
4009 void VM_SV_Cmd_Reset(void)
4011 World_End(&sv.world);
4012 if(prog->funcoffsets.SV_Shutdown)
4014 func_t s = prog->funcoffsets.SV_Shutdown;
4015 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4016 PRVM_ExecuteProgram(s,"SV_Shutdown() required");