6 //============================================================================
11 char *vm_sv_extensions =
16 "DP_CON_ALIASPARAMETERS "
22 "DP_CSQC_ENTITYNOCULL "
23 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
24 "DP_CSQC_MULTIFRAME_INTERPOLATION "
25 "DP_CSQC_SPAWNPARTICLE "
37 "DP_EF_RESTARTANIM_BIT "
42 "DP_ENT_CUSTOMCOLORMAP "
43 "DP_ENT_EXTERIORMODELTOCLIENT "
46 "DP_ENT_LOWPRECISION "
50 "DP_GFX_EXTERNALTEXTURES "
51 "DP_GFX_EXTERNALTEXTURES_PERMAP "
53 "DP_GFX_MODEL_INTERPOLATION "
54 "DP_GFX_QUAKE3MODELTAGS "
58 "DP_HALFLIFE_MAP_CVAR "
61 "DP_LIGHTSTYLE_STATICVALUE "
65 "DP_MOVETYPEBOUNCEMISSILE "
68 "DP_QC_ASINACOSATANATAN2TAN "
74 "DP_QC_CVAR_DEFSTRING "
75 "DP_QC_CVAR_DESCRIPTION "
82 "DP_QC_EXTRESPONSEPACKET "
84 "DP_QC_FINDCHAINFLAGS "
85 "DP_QC_FINDCHAINFLOAT "
86 "DP_QC_FINDCHAIN_TOFIELD "
92 "DP_QC_GETSURFACEPOINTATTRIBUTE "
94 "DP_QC_GETTAGINFO_BONEPROPERTIES "
96 "DP_QC_GETTIME_CDTRACK "
99 "DP_QC_MULTIPLETEMPSTRINGS "
100 "DP_QC_NUM_FOR_EDICT "
102 "DP_QC_SINCOSSQRTPOW "
104 "DP_QC_STRINGBUFFERS "
105 "DP_QC_STRINGBUFFERS_CVARLIST "
106 "DP_QC_STRINGCOLORFUNCTIONS "
107 "DP_QC_STRING_CASE_FUNCTIONS "
109 "DP_QC_TOKENIZEBYSEPARATOR "
110 "DP_QC_TOKENIZE_CONSOLE "
113 "DP_QC_TRACE_MOVETYPE_HITMODEL "
114 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
115 "DP_QC_UNLIMITEDTEMPSTRINGS "
118 "DP_QC_VECTOANGLES_WITH_ROLL "
119 "DP_QC_VECTORVECTORS "
126 "DP_SKELETONOBJECTS "
127 "DP_SND_DIRECTIONLESSATTNNONE "
135 "DP_SV_BOUNCEFACTOR "
136 "DP_SV_CLIENTCOLORS "
139 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
140 "DP_SV_DRAWONLYTOCLIENT "
143 "DP_SV_ENTITYCONTENTSTRANSITION "
144 "DP_SV_MODELFLAGS_AS_EFFECTS "
145 "DP_SV_MOVETYPESTEP_LANDEVENT "
147 "DP_SV_NODRAWTOCLIENT "
148 "DP_SV_ONENTITYNOSPAWNFUNCTION "
149 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
151 "DP_SV_PLAYERPHYSICS "
152 "DP_SV_POINTPARTICLES "
154 "DP_SV_PRECACHEANYTIME "
158 "DP_SV_ROTATINGBMODEL "
162 "DP_SV_SPAWNFUNC_PREFIX "
163 "DP_SV_WRITEPICTURE "
164 "DP_SV_WRITEUNTERMINATEDSTRING "
168 "DP_TE_EXPLOSIONRGB "
170 "DP_TE_PARTICLECUBE "
171 "DP_TE_PARTICLERAIN "
172 "DP_TE_PARTICLESNOW "
174 "DP_TE_QUADEFFECTS1 "
177 "DP_TE_STANDARDEFFECTBUILTINS "
178 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
182 "FTE_CSQC_SKELETONOBJECTS "
185 "KRIMZON_SV_PARSECLIENTCOMMAND "
188 "NEXUIZ_PLAYERMODEL "
190 "PRYDON_CLIENTCURSOR "
191 "TENEBRAE_GFX_DLIGHTS "
194 //"EXT_CSQC " // not ready yet
201 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.
203 setorigin (entity, origin)
206 static void VM_SV_setorigin (void)
211 VM_SAFEPARMCOUNT(2, VM_setorigin);
213 e = PRVM_G_EDICT(OFS_PARM0);
214 if (e == prog->edicts)
216 VM_Warning("setorigin: can not modify world entity\n");
219 if (e->priv.server->free)
221 VM_Warning("setorigin: can not modify free entity\n");
224 org = PRVM_G_VECTOR(OFS_PARM1);
225 VectorCopy (org, e->fields.server->origin);
229 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
230 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
234 for (i=0 ; i<3 ; i++)
236 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
238 // set derived values
239 VectorCopy (min, e->fields.server->mins);
240 VectorCopy (max, e->fields.server->maxs);
241 VectorSubtract (max, min, e->fields.server->size);
250 the size box is rotated by the current angle
251 LordHavoc: no it isn't...
253 setsize (entity, minvector, maxvector)
256 static void VM_SV_setsize (void)
261 VM_SAFEPARMCOUNT(3, VM_setsize);
263 e = PRVM_G_EDICT(OFS_PARM0);
264 if (e == prog->edicts)
266 VM_Warning("setsize: can not modify world entity\n");
269 if (e->priv.server->free)
271 VM_Warning("setsize: can not modify free entity\n");
274 min = PRVM_G_VECTOR(OFS_PARM1);
275 max = PRVM_G_VECTOR(OFS_PARM2);
276 SetMinMaxSize (e, min, max, false);
284 setmodel(entity, model)
287 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
288 static void VM_SV_setmodel (void)
294 VM_SAFEPARMCOUNT(2, VM_setmodel);
296 e = PRVM_G_EDICT(OFS_PARM0);
297 if (e == prog->edicts)
299 VM_Warning("setmodel: can not modify world entity\n");
302 if (e->priv.server->free)
304 VM_Warning("setmodel: can not modify free entity\n");
307 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
308 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
309 e->fields.server->modelindex = i;
311 mod = SV_GetModelByIndex(i);
315 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
316 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
318 SetMinMaxSize (e, quakemins, quakemaxs, true);
321 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
328 single print to a specific client
330 sprint(clientent, value)
333 static void VM_SV_sprint (void)
337 char string[VM_STRINGTEMP_LENGTH];
339 VM_VarString(1, string, sizeof(string));
341 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
343 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
344 // LordHavoc: div0 requested that sprintto world operate like print
351 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
353 VM_Warning("tried to centerprint to a non-client\n");
357 client = svs.clients + entnum-1;
358 if (!client->netconnection)
361 MSG_WriteChar(&client->netconnection->message,svc_print);
362 MSG_WriteString(&client->netconnection->message, string);
370 single print to a specific client
372 centerprint(clientent, value)
375 static void VM_SV_centerprint (void)
379 char string[VM_STRINGTEMP_LENGTH];
381 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint);
383 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
385 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
387 VM_Warning("tried to centerprint to a non-client\n");
391 client = svs.clients + entnum-1;
392 if (!client->netconnection)
395 VM_VarString(1, string, sizeof(string));
396 MSG_WriteChar(&client->netconnection->message,svc_centerprint);
397 MSG_WriteString(&client->netconnection->message, string);
404 particle(origin, color, count)
407 static void VM_SV_particle (void)
413 VM_SAFEPARMCOUNT(4, VM_SV_particle);
415 org = PRVM_G_VECTOR(OFS_PARM0);
416 dir = PRVM_G_VECTOR(OFS_PARM1);
417 color = PRVM_G_FLOAT(OFS_PARM2);
418 count = PRVM_G_FLOAT(OFS_PARM3);
419 SV_StartParticle (org, dir, (int)color, (int)count);
429 static void VM_SV_ambientsound (void)
433 float vol, attenuation;
436 VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
438 pos = PRVM_G_VECTOR (OFS_PARM0);
439 samp = PRVM_G_STRING(OFS_PARM1);
440 vol = PRVM_G_FLOAT(OFS_PARM2);
441 attenuation = PRVM_G_FLOAT(OFS_PARM3);
443 // check to see if samp was properly precached
444 soundnum = SV_SoundIndex(samp, 1);
452 // add an svc_spawnambient command to the level signon packet
455 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
457 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
459 MSG_WriteVector(&sv.signon, pos, sv.protocol);
461 if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
462 MSG_WriteShort (&sv.signon, soundnum);
464 MSG_WriteByte (&sv.signon, soundnum);
466 MSG_WriteByte (&sv.signon, (int)(vol*255));
467 MSG_WriteByte (&sv.signon, (int)(attenuation*64));
475 Each entity can have eight independant sound sources, like voice,
478 Channel 0 is an auto-allocate channel, the others override anything
479 already running on that entity/channel pair.
481 An attenuation of 0 will play full volume everywhere in the level.
482 Larger attenuations will drop off.
486 static void VM_SV_sound (void)
490 prvm_edict_t *entity;
494 VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
496 entity = PRVM_G_EDICT(OFS_PARM0);
497 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
498 sample = PRVM_G_STRING(OFS_PARM2);
499 volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
500 attenuation = PRVM_G_FLOAT(OFS_PARM4);
503 Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
507 if (volume < 0 || volume > 255)
509 VM_Warning("SV_StartSound: volume must be in range 0-1\n");
513 if (attenuation < 0 || attenuation > 4)
515 VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
519 if (channel < 0 || channel > 7)
521 VM_Warning("SV_StartSound: channel must be in range 0-7\n");
525 SV_StartSound (entity, channel, sample, volume, attenuation);
532 Follows the same logic as VM_SV_sound, except instead of
533 an entity, an origin for the sound is provided, and channel
534 is omitted (since no entity is being tracked).
538 static void VM_SV_pointsound(void)
545 VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
547 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
548 sample = PRVM_G_STRING(OFS_PARM1);
549 volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
550 attenuation = PRVM_G_FLOAT(OFS_PARM3);
552 if (volume < 0 || volume > 255)
554 VM_Warning("SV_StartPointSound: volume must be in range 0-1\n");
558 if (attenuation < 0 || attenuation > 4)
560 VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
564 SV_StartPointSound (org, sample, volume, attenuation);
571 Used for use tracing and shot targeting
572 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
573 if the tryents flag is set.
575 traceline (vector1, vector2, movetype, ignore)
578 static void VM_SV_traceline (void)
585 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion
587 prog->xfunction->builtinsprofile += 30;
589 v1 = PRVM_G_VECTOR(OFS_PARM0);
590 v2 = PRVM_G_VECTOR(OFS_PARM1);
591 move = (int)PRVM_G_FLOAT(OFS_PARM2);
592 ent = PRVM_G_EDICT(OFS_PARM3);
594 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]))
595 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));
597 trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
599 VM_SetTraceGlobals(&trace);
607 Used for use tracing and shot targeting
608 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
609 if the tryents flag is set.
611 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
614 // LordHavoc: added this for my own use, VERY useful, similar to traceline
615 static void VM_SV_tracebox (void)
617 float *v1, *v2, *m1, *m2;
622 VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion
624 prog->xfunction->builtinsprofile += 30;
626 v1 = PRVM_G_VECTOR(OFS_PARM0);
627 m1 = PRVM_G_VECTOR(OFS_PARM1);
628 m2 = PRVM_G_VECTOR(OFS_PARM2);
629 v2 = PRVM_G_VECTOR(OFS_PARM3);
630 move = (int)PRVM_G_FLOAT(OFS_PARM4);
631 ent = PRVM_G_EDICT(OFS_PARM5);
633 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]))
634 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));
636 trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
638 VM_SetTraceGlobals(&trace);
641 static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
646 vec3_t original_origin;
647 vec3_t original_velocity;
648 vec3_t original_angles;
649 vec3_t original_avelocity;
653 VectorCopy(tossent->fields.server->origin , original_origin );
654 VectorCopy(tossent->fields.server->velocity , original_velocity );
655 VectorCopy(tossent->fields.server->angles , original_angles );
656 VectorCopy(tossent->fields.server->avelocity, original_avelocity);
658 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
659 if (val != NULL && val->_float != 0)
660 gravity = val->_float;
663 gravity *= sv_gravity.value * 0.025;
665 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
667 SV_CheckVelocity (tossent);
668 tossent->fields.server->velocity[2] -= gravity;
669 VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
670 VectorScale (tossent->fields.server->velocity, 0.05, move);
671 VectorAdd (tossent->fields.server->origin, move, end);
672 trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
673 VectorCopy (trace.endpos, tossent->fields.server->origin);
674 tossent->fields.server->velocity[2] -= gravity;
676 if (trace.fraction < 1)
680 VectorCopy(original_origin , tossent->fields.server->origin );
681 VectorCopy(original_velocity , tossent->fields.server->velocity );
682 VectorCopy(original_angles , tossent->fields.server->angles );
683 VectorCopy(original_avelocity, tossent->fields.server->avelocity);
688 static void VM_SV_tracetoss (void)
692 prvm_edict_t *ignore;
694 VM_SAFEPARMCOUNT(2, VM_SV_tracetoss);
696 prog->xfunction->builtinsprofile += 600;
698 ent = PRVM_G_EDICT(OFS_PARM0);
699 if (ent == prog->edicts)
701 VM_Warning("tracetoss: can not use world entity\n");
704 ignore = PRVM_G_EDICT(OFS_PARM1);
706 trace = SV_Trace_Toss (ent, ignore);
708 VM_SetTraceGlobals(&trace);
711 //============================================================================
713 static int checkpvsbytes;
714 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
716 static int VM_SV_newcheckclient (int check)
722 // cycle to the next one
724 check = bound(1, check, svs.maxclients);
725 if (check == svs.maxclients)
733 prog->xfunction->builtinsprofile++;
735 if (i == svs.maxclients+1)
737 // look up the client's edict
738 ent = PRVM_EDICT_NUM(i);
739 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
740 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
742 // found a valid client (possibly the same one again)
746 // get the PVS for the entity
747 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
749 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
750 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
759 Returns a client (or object that has a client enemy) that would be a
762 If there is more than one valid option, they are cycled each frame
764 If (self.origin + self.viewofs) is not in the PVS of the current target,
765 it is not returned at all.
770 int c_invis, c_notvis;
771 static void VM_SV_checkclient (void)
773 prvm_edict_t *ent, *self;
776 VM_SAFEPARMCOUNT(0, VM_SV_checkclient);
778 // find a new check if on a new frame
779 if (sv.time - sv.lastchecktime >= 0.1)
781 sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
782 sv.lastchecktime = sv.time;
785 // return check if it might be visible
786 ent = PRVM_EDICT_NUM(sv.lastcheck);
787 if (ent->priv.server->free || ent->fields.server->health <= 0)
789 VM_RETURN_EDICT(prog->edicts);
793 // if current entity can't possibly see the check entity, return 0
794 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
795 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
796 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
799 VM_RETURN_EDICT(prog->edicts);
803 // might be able to see it
805 VM_RETURN_EDICT(ent);
808 //============================================================================
814 Checks if an entity is in a point's PVS.
815 Should be fast but can be inexact.
817 float checkpvs(vector viewpos, entity viewee) = #240;
820 static void VM_SV_checkpvs (void)
823 prvm_edict_t *viewee;
828 unsigned char fatpvs[MAX_MAP_LEAFS/8];
831 VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
832 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
833 viewee = PRVM_G_EDICT(OFS_PARM1);
835 if(viewee->priv.server->free)
837 VM_Warning("checkpvs: can not check free entity\n");
838 PRVM_G_FLOAT(OFS_RETURN) = 4;
843 if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
845 // no PVS support on this worldmodel... darn
846 PRVM_G_FLOAT(OFS_RETURN) = 3;
849 pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
852 // viewpos isn't in any PVS... darn
853 PRVM_G_FLOAT(OFS_RETURN) = 2;
856 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
858 // using fat PVS like FTEQW does (slow)
859 if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
861 // no PVS support on this worldmodel... darn
862 PRVM_G_FLOAT(OFS_RETURN) = 3;
865 fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
868 // viewpos isn't in any PVS... darn
869 PRVM_G_FLOAT(OFS_RETURN) = 2;
872 PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
881 Sends text over to the client's execution buffer
883 stuffcmd (clientent, value, ...)
886 static void VM_SV_stuffcmd (void)
890 char string[VM_STRINGTEMP_LENGTH];
892 VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd);
894 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
895 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
897 VM_Warning("Can't stuffcmd to a non-client\n");
901 VM_VarString(1, string, sizeof(string));
904 host_client = svs.clients + entnum-1;
905 Host_ClientCommands ("%s", string);
913 Returns a chain of entities that have origins within a spherical area
915 findradius (origin, radius)
918 static void VM_SV_findradius (void)
920 prvm_edict_t *ent, *chain;
921 vec_t radius, radius2;
922 vec3_t org, eorg, mins, maxs;
925 static prvm_edict_t *touchedicts[MAX_EDICTS];
928 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
931 chainfield = PRVM_G_INT(OFS_PARM2);
933 chainfield = prog->fieldoffsets.chain;
935 PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
937 chain = (prvm_edict_t *)prog->edicts;
939 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
940 radius = PRVM_G_FLOAT(OFS_PARM1);
941 radius2 = radius * radius;
943 mins[0] = org[0] - (radius + 1);
944 mins[1] = org[1] - (radius + 1);
945 mins[2] = org[2] - (radius + 1);
946 maxs[0] = org[0] + (radius + 1);
947 maxs[1] = org[1] + (radius + 1);
948 maxs[2] = org[2] + (radius + 1);
949 numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
950 if (numtouchedicts > MAX_EDICTS)
952 // this never happens
953 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
954 numtouchedicts = MAX_EDICTS;
956 for (i = 0;i < numtouchedicts;i++)
958 ent = touchedicts[i];
959 prog->xfunction->builtinsprofile++;
960 // Quake did not return non-solid entities but darkplaces does
961 // (note: this is the reason you can't blow up fallen zombies)
962 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
964 // LordHavoc: compare against bounding box rather than center so it
965 // doesn't miss large objects, and use DotProduct instead of Length
966 // for a major speedup
967 VectorSubtract(org, ent->fields.server->origin, eorg);
968 if (sv_gameplayfix_findradiusdistancetobox.integer)
970 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
971 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
972 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
975 VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
976 if (DotProduct(eorg, eorg) < radius2)
978 PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
983 VM_RETURN_EDICT(chain);
986 static void VM_SV_precache_sound (void)
988 VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
989 PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
992 static void VM_SV_precache_model (void)
994 VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
995 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
996 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1003 float(float yaw, float dist[, settrace]) walkmove
1006 static void VM_SV_walkmove (void)
1015 VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove);
1017 // assume failure if it returns early
1018 PRVM_G_FLOAT(OFS_RETURN) = 0;
1020 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1021 if (ent == prog->edicts)
1023 VM_Warning("walkmove: can not modify world entity\n");
1026 if (ent->priv.server->free)
1028 VM_Warning("walkmove: can not modify free entity\n");
1031 yaw = PRVM_G_FLOAT(OFS_PARM0);
1032 dist = PRVM_G_FLOAT(OFS_PARM1);
1033 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
1035 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1038 yaw = yaw*M_PI*2 / 360;
1040 move[0] = cos(yaw)*dist;
1041 move[1] = sin(yaw)*dist;
1044 // save program state, because SV_movestep may call other progs
1045 oldf = prog->xfunction;
1046 oldself = prog->globals.server->self;
1048 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
1051 // restore program state
1052 prog->xfunction = oldf;
1053 prog->globals.server->self = oldself;
1063 static void VM_SV_droptofloor (void)
1069 VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
1071 // assume failure if it returns early
1072 PRVM_G_FLOAT(OFS_RETURN) = 0;
1074 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1075 if (ent == prog->edicts)
1077 VM_Warning("droptofloor: can not modify world entity\n");
1080 if (ent->priv.server->free)
1082 VM_Warning("droptofloor: can not modify free entity\n");
1086 VectorCopy (ent->fields.server->origin, end);
1089 if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
1090 SV_UnstickEntity(ent);
1092 trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1093 if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
1096 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]);
1097 VectorAdd(ent->fields.server->origin, offset, org);
1098 trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
1099 VectorSubtract(trace.endpos, offset, trace.endpos);
1100 if (trace.startsolid)
1102 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]);
1103 SV_UnstickEntity(ent);
1105 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1106 ent->fields.server->groundentity = 0;
1107 PRVM_G_FLOAT(OFS_RETURN) = 1;
1109 else if (trace.fraction < 1)
1111 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]);
1112 VectorCopy (trace.endpos, ent->fields.server->origin);
1113 SV_UnstickEntity(ent);
1115 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1116 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1117 PRVM_G_FLOAT(OFS_RETURN) = 1;
1118 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1119 ent->priv.server->suspendedinairflag = true;
1124 if (trace.fraction != 1)
1126 if (trace.fraction < 1)
1127 VectorCopy (trace.endpos, ent->fields.server->origin);
1129 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1130 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1131 PRVM_G_FLOAT(OFS_RETURN) = 1;
1132 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1133 ent->priv.server->suspendedinairflag = true;
1142 void(float style, string value) lightstyle
1145 static void VM_SV_lightstyle (void)
1152 VM_SAFEPARMCOUNT(2, VM_SV_lightstyle);
1154 style = (int)PRVM_G_FLOAT(OFS_PARM0);
1155 val = PRVM_G_STRING(OFS_PARM1);
1157 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
1158 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
1161 // change the string in sv
1162 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1164 // send message to all clients on this server
1165 if (sv.state != ss_active)
1168 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1170 if (client->active && client->netconnection)
1172 MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
1173 MSG_WriteChar (&client->netconnection->message,style);
1174 MSG_WriteString (&client->netconnection->message, val);
1184 static void VM_SV_checkbottom (void)
1186 VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
1187 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1195 static void VM_SV_pointcontents (void)
1197 VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
1198 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1205 Pick a vector for the player to shoot along
1206 vector aim(entity, missilespeed)
1209 static void VM_SV_aim (void)
1211 prvm_edict_t *ent, *check, *bestent;
1212 vec3_t start, dir, end, bestdir;
1215 float dist, bestdist;
1218 VM_SAFEPARMCOUNT(2, VM_SV_aim);
1220 // assume failure if it returns early
1221 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1222 // if sv_aim is so high it can't possibly accept anything, skip out early
1223 if (sv_aim.value >= 1)
1226 ent = PRVM_G_EDICT(OFS_PARM0);
1227 if (ent == prog->edicts)
1229 VM_Warning("aim: can not use world entity\n");
1232 if (ent->priv.server->free)
1234 VM_Warning("aim: can not use free entity\n");
1237 speed = PRVM_G_FLOAT(OFS_PARM1);
1239 VectorCopy (ent->fields.server->origin, start);
1242 // try sending a trace straight
1243 VectorCopy (prog->globals.server->v_forward, dir);
1244 VectorMA (start, 2048, dir, end);
1245 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1246 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1247 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1249 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1254 // try all possible entities
1255 VectorCopy (dir, bestdir);
1256 bestdist = sv_aim.value;
1259 check = PRVM_NEXT_EDICT(prog->edicts);
1260 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1262 prog->xfunction->builtinsprofile++;
1263 if (check->fields.server->takedamage != DAMAGE_AIM)
1267 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1268 continue; // don't aim at teammate
1269 for (j=0 ; j<3 ; j++)
1270 end[j] = check->fields.server->origin[j]
1271 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1272 VectorSubtract (end, start, dir);
1273 VectorNormalize (dir);
1274 dist = DotProduct (dir, prog->globals.server->v_forward);
1275 if (dist < bestdist)
1276 continue; // to far to turn
1277 tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
1278 if (tr.ent == check)
1279 { // can shoot at this one
1287 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1288 dist = DotProduct (dir, prog->globals.server->v_forward);
1289 VectorScale (prog->globals.server->v_forward, dist, end);
1291 VectorNormalize (end);
1292 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1296 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1301 ===============================================================================
1305 ===============================================================================
1308 #define MSG_BROADCAST 0 // unreliable to all
1309 #define MSG_ONE 1 // reliable to one (msg_entity)
1310 #define MSG_ALL 2 // reliable to all
1311 #define MSG_INIT 3 // write to the init string
1312 #define MSG_ENTITY 5
1314 sizebuf_t *WriteDest (void)
1320 dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1324 return &sv.datagram;
1327 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1328 entnum = PRVM_NUM_FOR_EDICT(ent);
1329 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1331 VM_Warning ("WriteDest: tried to write to non-client\n");
1332 return &sv.reliable_datagram;
1335 return &svs.clients[entnum-1].netconnection->message;
1338 VM_Warning ("WriteDest: bad destination\n");
1340 return &sv.reliable_datagram;
1346 return sv.writeentitiestoclient_msg;
1352 static void VM_SV_WriteByte (void)
1354 VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
1355 MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1358 static void VM_SV_WriteChar (void)
1360 VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
1361 MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1364 static void VM_SV_WriteShort (void)
1366 VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
1367 MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1370 static void VM_SV_WriteLong (void)
1372 VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
1373 MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1376 static void VM_SV_WriteAngle (void)
1378 VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
1379 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1382 static void VM_SV_WriteCoord (void)
1384 VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
1385 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1388 static void VM_SV_WriteString (void)
1390 VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
1391 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1394 static void VM_SV_WriteUnterminatedString (void)
1396 VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
1397 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 static void VM_SV_WriteByteINT (void)
1408 VM_SAFEPARMCOUNT(2, VM_SV_WriteByteINT);
1409 MSG_WriteByte (WriteDest(), PRVM_G_INT(OFS_PARM1));
1412 static void VM_SV_WriteCharINT (void)
1414 VM_SAFEPARMCOUNT(2, VM_SV_WriteCharINT);
1415 MSG_WriteChar (WriteDest(), PRVM_G_INT(OFS_PARM1));
1418 static void VM_SV_WriteShortINT (void)
1420 VM_SAFEPARMCOUNT(2, VM_SV_WriteShortINT);
1421 MSG_WriteShort (WriteDest(), PRVM_G_INT(OFS_PARM1));
1424 static void VM_SV_WriteLongINT (void)
1426 VM_SAFEPARMCOUNT(2, VM_SV_WriteLongINT);
1427 MSG_WriteLong (WriteDest(), PRVM_G_INT(OFS_PARM1));
1431 // writes a picture as at most size bytes of data
1433 // IMGNAME \0 SIZE(short) IMGDATA
1434 // if failed to read/compress:
1436 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
1437 static void VM_SV_WritePicture (void)
1439 const char *imgname;
1443 VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
1445 imgname = PRVM_G_STRING(OFS_PARM1);
1446 size = (int) PRVM_G_FLOAT(OFS_PARM2);
1450 MSG_WriteString(WriteDest(), imgname);
1451 if(Image_Compress(imgname, size, &buf, &size))
1454 MSG_WriteShort(WriteDest(), size);
1455 SZ_Write(WriteDest(), (unsigned char *) buf, size);
1460 MSG_WriteShort(WriteDest(), 0);
1464 //////////////////////////////////////////////////////////
1466 static void VM_SV_makestatic (void)
1471 // allow 0 parameters due to an id1 qc bug in which this function is used
1472 // with no parameters (but directly after setmodel with self in OFS_PARM0)
1473 VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
1475 if (prog->argc >= 1)
1476 ent = PRVM_G_EDICT(OFS_PARM0);
1478 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1479 if (ent == prog->edicts)
1481 VM_Warning("makestatic: can not modify world entity\n");
1484 if (ent->priv.server->free)
1486 VM_Warning("makestatic: can not modify free entity\n");
1491 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1496 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1497 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1498 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1500 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1502 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1503 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1504 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1508 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1509 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1510 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1513 MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1514 MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1515 for (i=0 ; i<3 ; i++)
1517 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1518 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1521 // throw the entity away now
1525 //=============================================================================
1532 static void VM_SV_setspawnparms (void)
1538 VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
1540 ent = PRVM_G_EDICT(OFS_PARM0);
1541 i = PRVM_NUM_FOR_EDICT(ent);
1542 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1544 Con_Print("tried to setspawnparms on a non-client\n");
1548 // copy spawn parms out of the client_t
1549 client = svs.clients + i-1;
1550 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1551 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1558 Returns a color vector indicating the lighting at the requested point.
1560 (Internal Operation note: actually measures the light beneath the point, just like
1561 the model lighting on the client)
1566 static void VM_SV_getlight (void)
1568 vec3_t ambientcolor, diffusecolor, diffusenormal;
1570 VM_SAFEPARMCOUNT(1, VM_SV_getlight);
1571 p = PRVM_G_VECTOR(OFS_PARM0);
1572 VectorClear(ambientcolor);
1573 VectorClear(diffusecolor);
1574 VectorClear(diffusenormal);
1575 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1576 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1577 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1582 unsigned char type; // 1/2/8 or other value if isn't used
1586 static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32
1587 static int vm_customstats_last;
1589 void VM_CustomStats_Clear (void)
1593 Z_Free(vm_customstats);
1594 vm_customstats = NULL;
1595 vm_customstats_last = -1;
1599 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1607 for(i=0; i<vm_customstats_last+1 ;i++)
1609 if(!vm_customstats[i].type)
1611 switch(vm_customstats[i].type)
1613 //string as 16 bytes
1616 strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
1617 stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
1618 stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
1619 stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
1620 stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
1622 //float field sent as-is
1624 stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
1626 //integer value of float field
1628 stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
1636 // void(float index, float type, .void field) SV_AddStat = #232;
1637 // Set up an auto-sent player stat.
1638 // Client's get thier own fields sent to them. Index may not be less than 32.
1639 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1640 // 1: string (4 stats carrying a total of 16 charactures)
1641 // 2: float (one stat, float converted to an integer for transportation)
1642 // 8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1643 static void VM_SV_AddStat (void)
1648 VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
1652 vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
1655 VM_Warning("PF_SV_AddStat: not enough memory\n");
1659 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1660 type = (int)PRVM_G_FLOAT(OFS_PARM1);
1661 off = PRVM_G_INT (OFS_PARM2);
1666 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1669 if(i >= (MAX_CL_STATS-32))
1671 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1674 if(i > (MAX_CL_STATS-32-4) && type == 1)
1676 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1679 vm_customstats[i].type = type;
1680 vm_customstats[i].fieldoffset = off;
1681 if(vm_customstats_last < i)
1682 vm_customstats_last = i;
1689 copies data from one entity to another
1691 copyentity(src, dst)
1694 static void VM_SV_copyentity (void)
1696 prvm_edict_t *in, *out;
1697 VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
1698 in = PRVM_G_EDICT(OFS_PARM0);
1699 if (in == prog->edicts)
1701 VM_Warning("copyentity: can not read world entity\n");
1704 if (in->priv.server->free)
1706 VM_Warning("copyentity: can not read free entity\n");
1709 out = PRVM_G_EDICT(OFS_PARM1);
1710 if (out == prog->edicts)
1712 VM_Warning("copyentity: can not modify world entity\n");
1715 if (out->priv.server->free)
1717 VM_Warning("copyentity: can not modify free entity\n");
1720 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1729 sets the color of a client and broadcasts the update to all connected clients
1731 setcolor(clientent, value)
1734 static void VM_SV_setcolor (void)
1740 VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
1741 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1742 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1744 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1746 Con_Print("tried to setcolor a non-client\n");
1750 client = svs.clients + entnum-1;
1753 if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
1755 client->edict->fields.server->team = (i & 15) + 1;
1758 if (client->old_colors != client->colors)
1760 client->old_colors = client->colors;
1761 // send notification to all clients
1762 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1763 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1764 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1772 effect(origin, modelname, startframe, framecount, framerate)
1775 static void VM_SV_effect (void)
1779 VM_SAFEPARMCOUNT(5, VM_SV_effect);
1780 s = PRVM_G_STRING(OFS_PARM1);
1783 VM_Warning("effect: no model specified\n");
1787 i = SV_ModelIndex(s, 1);
1790 VM_Warning("effect: model not precached\n");
1794 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1796 VM_Warning("effect: framecount < 1\n");
1800 if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1802 VM_Warning("effect: framerate < 1\n");
1806 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));
1809 static void VM_SV_te_blood (void)
1811 VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
1812 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1814 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1815 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1817 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1818 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1819 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1821 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1822 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1823 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1825 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1826 SV_FlushBroadcastMessages();
1829 static void VM_SV_te_bloodshower (void)
1831 VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
1832 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1834 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1835 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1837 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1838 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1839 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1841 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1842 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1843 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1845 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1847 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1848 SV_FlushBroadcastMessages();
1851 static void VM_SV_te_explosionrgb (void)
1853 VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
1854 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1855 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1857 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1858 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1859 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1861 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1862 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1863 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1864 SV_FlushBroadcastMessages();
1867 static void VM_SV_te_particlecube (void)
1869 VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
1870 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1872 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1873 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1875 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1876 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1877 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1879 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1880 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1881 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1883 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1884 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1885 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1887 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1889 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1890 // gravity true/false
1891 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1893 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1894 SV_FlushBroadcastMessages();
1897 static void VM_SV_te_particlerain (void)
1899 VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
1900 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1902 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1903 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1905 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1906 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1907 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1909 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1910 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1911 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1913 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1914 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1915 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1917 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1919 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1920 SV_FlushBroadcastMessages();
1923 static void VM_SV_te_particlesnow (void)
1925 VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
1926 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1928 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1929 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1931 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1932 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1933 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1935 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1936 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1937 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1939 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1940 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1941 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1943 MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1945 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1946 SV_FlushBroadcastMessages();
1949 static void VM_SV_te_spark (void)
1951 VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
1952 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1954 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1955 MSG_WriteByte(&sv.datagram, TE_SPARK);
1957 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1958 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1959 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1961 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1962 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1963 MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1965 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1966 SV_FlushBroadcastMessages();
1969 static void VM_SV_te_gunshotquad (void)
1971 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
1972 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1973 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1975 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1976 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1977 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1978 SV_FlushBroadcastMessages();
1981 static void VM_SV_te_spikequad (void)
1983 VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
1984 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1985 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1987 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1988 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1989 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1990 SV_FlushBroadcastMessages();
1993 static void VM_SV_te_superspikequad (void)
1995 VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
1996 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1997 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1999 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2000 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2001 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2002 SV_FlushBroadcastMessages();
2005 static void VM_SV_te_explosionquad (void)
2007 VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
2008 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2009 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2011 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2012 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2013 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2014 SV_FlushBroadcastMessages();
2017 static void VM_SV_te_smallflash (void)
2019 VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
2020 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2021 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2023 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2024 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2025 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2026 SV_FlushBroadcastMessages();
2029 static void VM_SV_te_customflash (void)
2031 VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
2032 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2034 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2035 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2037 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2038 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2039 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2041 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2043 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2045 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2046 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2047 MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2048 SV_FlushBroadcastMessages();
2051 static void VM_SV_te_gunshot (void)
2053 VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
2054 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2055 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2057 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2058 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2059 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2060 SV_FlushBroadcastMessages();
2063 static void VM_SV_te_spike (void)
2065 VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
2066 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2067 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2069 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2070 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2071 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2072 SV_FlushBroadcastMessages();
2075 static void VM_SV_te_superspike (void)
2077 VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
2078 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2079 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2081 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2082 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2083 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2084 SV_FlushBroadcastMessages();
2087 static void VM_SV_te_explosion (void)
2089 VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
2090 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2091 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2093 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2094 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2095 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2096 SV_FlushBroadcastMessages();
2099 static void VM_SV_te_tarexplosion (void)
2101 VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
2102 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2103 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2105 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2106 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2107 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2108 SV_FlushBroadcastMessages();
2111 static void VM_SV_te_wizspike (void)
2113 VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
2114 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2115 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2117 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2118 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2119 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2120 SV_FlushBroadcastMessages();
2123 static void VM_SV_te_knightspike (void)
2125 VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
2126 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2127 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2129 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2130 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2131 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2132 SV_FlushBroadcastMessages();
2135 static void VM_SV_te_lavasplash (void)
2137 VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
2138 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2139 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2141 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2142 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2143 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2144 SV_FlushBroadcastMessages();
2147 static void VM_SV_te_teleport (void)
2149 VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
2150 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2151 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2153 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2154 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2155 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2156 SV_FlushBroadcastMessages();
2159 static void VM_SV_te_explosion2 (void)
2161 VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
2162 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2163 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2165 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2166 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2167 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2169 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2170 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2171 SV_FlushBroadcastMessages();
2174 static void VM_SV_te_lightning1 (void)
2176 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
2177 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2178 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2180 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2182 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2183 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2184 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2186 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2187 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2188 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2189 SV_FlushBroadcastMessages();
2192 static void VM_SV_te_lightning2 (void)
2194 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
2195 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2196 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2198 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2200 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2201 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2202 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2204 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2205 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2206 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2207 SV_FlushBroadcastMessages();
2210 static void VM_SV_te_lightning3 (void)
2212 VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
2213 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2214 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2216 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2218 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2222 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2223 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2224 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2225 SV_FlushBroadcastMessages();
2228 static void VM_SV_te_beam (void)
2230 VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
2231 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2232 MSG_WriteByte(&sv.datagram, TE_BEAM);
2234 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2236 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2237 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2238 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2240 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2243 SV_FlushBroadcastMessages();
2246 static void VM_SV_te_plasmaburn (void)
2248 VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
2249 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2250 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2251 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2252 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2253 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2254 SV_FlushBroadcastMessages();
2257 static void VM_SV_te_flamejet (void)
2259 VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
2260 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2261 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2263 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2264 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2265 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2267 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2268 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2271 MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2272 SV_FlushBroadcastMessages();
2275 void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2278 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2280 bestdist = 1000000000;
2282 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2284 // clip original point to each triangle of the surface and find the
2285 // triangle that is closest
2286 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2287 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2288 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2289 TriangleNormal(v[0], v[1], v[2], facenormal);
2290 VectorNormalize(facenormal);
2291 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2292 VectorMA(p, offsetdist, facenormal, temp);
2293 for (j = 0, k = 2;j < 3;k = j, j++)
2295 VectorSubtract(v[k], v[j], edgenormal);
2296 CrossProduct(edgenormal, facenormal, sidenormal);
2297 VectorNormalize(sidenormal);
2298 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2300 VectorMA(temp, offsetdist, sidenormal, temp);
2302 dist = VectorDistance2(temp, p);
2303 if (bestdist > dist)
2306 VectorCopy(temp, out);
2311 #define getmodel SV_GetModelFromEdict
2313 static msurface_t *getsurface(dp_model_t *model, int surfacenum)
2315 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2317 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2321 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2322 static void VM_SV_getsurfacenumpoints(void)
2325 msurface_t *surface;
2326 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
2327 // return 0 if no such surface
2328 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2330 PRVM_G_FLOAT(OFS_RETURN) = 0;
2334 // note: this (incorrectly) assumes it is a simple polygon
2335 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2337 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2338 static void VM_SV_getsurfacepoint(void)
2342 msurface_t *surface;
2344 VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
2345 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2346 ed = PRVM_G_EDICT(OFS_PARM0);
2347 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2349 // note: this (incorrectly) assumes it is a simple polygon
2350 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2351 if (pointnum < 0 || pointnum >= surface->num_vertices)
2353 // FIXME: implement rotation/scaling
2354 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2356 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
2357 // float SPA_POSITION = 0;
2358 // float SPA_S_AXIS = 1;
2359 // float SPA_T_AXIS = 2;
2360 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2361 // float SPA_TEXCOORDS0 = 4;
2362 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2363 // float SPA_LIGHTMAP0_COLOR = 6;
2364 static void VM_SV_getsurfacepointattribute(void)
2368 msurface_t *surface;
2372 VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
2373 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2374 ed = PRVM_G_EDICT(OFS_PARM0);
2375 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2377 // note: this (incorrectly) assumes it is a simple polygon
2378 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2379 if (pointnum < 0 || pointnum >= surface->num_vertices)
2381 // FIXME: implement rotation/scaling
2382 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
2384 switch( attributetype ) {
2385 // float SPA_POSITION = 0;
2387 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2389 // float SPA_S_AXIS = 1;
2391 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2393 // float SPA_T_AXIS = 2;
2395 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2397 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
2399 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
2401 // float SPA_TEXCOORDS0 = 4;
2403 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2404 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
2405 ret[0] = texcoord[0];
2406 ret[1] = texcoord[1];
2410 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
2412 float *ret = PRVM_G_VECTOR(OFS_RETURN);
2413 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
2414 ret[0] = texcoord[0];
2415 ret[1] = texcoord[1];
2419 // float SPA_LIGHTMAP0_COLOR = 6;
2421 // ignore alpha for now..
2422 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
2425 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
2429 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2430 static void VM_SV_getsurfacenormal(void)
2433 msurface_t *surface;
2435 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
2436 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2437 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2439 // FIXME: implement rotation/scaling
2440 // note: this (incorrectly) assumes it is a simple polygon
2441 // note: this only returns the first triangle, so it doesn't work very
2442 // well for curved surfaces or arbitrary meshes
2443 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);
2444 VectorNormalize(normal);
2445 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2447 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2448 static void VM_SV_getsurfacetexture(void)
2451 msurface_t *surface;
2452 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
2453 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2454 if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2456 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
2458 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2459 static void VM_SV_getsurfacenearpoint(void)
2461 int surfacenum, best;
2463 vec_t dist, bestdist;
2466 msurface_t *surface;
2468 VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
2469 PRVM_G_FLOAT(OFS_RETURN) = -1;
2470 ed = PRVM_G_EDICT(OFS_PARM0);
2471 point = PRVM_G_VECTOR(OFS_PARM1);
2473 if (!ed || ed->priv.server->free)
2475 model = getmodel(ed);
2476 if (!model || !model->num_surfaces)
2479 // FIXME: implement rotation/scaling
2480 VectorSubtract(point, ed->fields.server->origin, p);
2482 bestdist = 1000000000;
2483 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2485 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2486 // first see if the nearest point on the surface's box is closer than the previous match
2487 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2488 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2489 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2490 dist = VectorLength2(clipped);
2491 if (dist < bestdist)
2493 // it is, check the nearest point on the actual geometry
2494 clippointtosurface(model, surface, p, clipped);
2495 VectorSubtract(clipped, p, clipped);
2496 dist += VectorLength2(clipped);
2497 if (dist < bestdist)
2499 // that's closer too, store it as the best match
2505 PRVM_G_FLOAT(OFS_RETURN) = best;
2507 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2508 static void VM_SV_getsurfaceclippedpoint(void)
2512 msurface_t *surface;
2514 VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
2515 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2516 ed = PRVM_G_EDICT(OFS_PARM0);
2517 if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2519 // FIXME: implement rotation/scaling
2520 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2521 clippointtosurface(model, surface, p, out);
2522 // FIXME: implement rotation/scaling
2523 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2526 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2527 //this function originally written by KrimZon, made shorter by LordHavoc
2528 static void VM_SV_clientcommand (void)
2530 client_t *temp_client;
2532 VM_SAFEPARMCOUNT(2, VM_SV_clientcommand);
2534 //find client for this entity
2535 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2536 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2538 Con_Print("PF_clientcommand: entity is not a client\n");
2542 temp_client = host_client;
2543 host_client = svs.clients + i;
2544 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2545 host_client = temp_client;
2548 //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)
2549 static void VM_SV_setattachment (void)
2551 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2552 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2553 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2556 VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
2558 if (e == prog->edicts)
2560 VM_Warning("setattachment: can not modify world entity\n");
2563 if (e->priv.server->free)
2565 VM_Warning("setattachment: can not modify free entity\n");
2569 if (tagentity == NULL)
2570 tagentity = prog->edicts;
2572 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2574 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2576 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2579 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2581 model = SV_GetModelFromEdict(tagentity);
2584 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2586 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);
2589 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));
2593 /////////////////////////////////////////
2594 // DP_MD3_TAGINFO extension coded by VorteX
2596 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2600 i = (int)e->fields.server->modelindex;
2601 if (i < 1 || i >= MAX_MODELS)
2604 return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, tagname);
2607 int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
2614 Matrix4x4_CreateIdentity(tag_localmatrix);
2616 if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
2618 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
2629 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2633 float pitchsign = 1;
2636 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2637 if (val && val->_float != 0)
2638 scale = val->_float;
2641 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);
2644 pitchsign = SV_GetPitchSign(ent);
2645 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);
2649 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2652 if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->num_bones)
2654 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2655 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2656 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2657 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
2659 *out = identitymatrix;
2663 // Warnings/errors code:
2664 // 0 - normal (everything all-right)
2667 // 3 - null or non-precached model
2668 // 4 - no tags with requested index
2669 // 5 - runaway loop at attachment chain
2670 extern cvar_t cl_bob;
2671 extern cvar_t cl_bobcycle;
2672 extern cvar_t cl_bobup;
2673 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2677 int modelindex, attachloop;
2678 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2681 *out = identitymatrix; // warnings and errors return identical matrix
2683 if (ent == prog->edicts)
2685 if (ent->priv.server->free)
2688 modelindex = (int)ent->fields.server->modelindex;
2689 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2692 model = SV_GetModelByIndex(modelindex);
2694 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
2695 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
2696 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
2698 tagmatrix = identitymatrix;
2699 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2703 if (attachloop >= 256) // prevent runaway looping
2705 // apply transformation by child's tagindex on parent entity and then
2706 // by parent entity itself
2707 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2708 if (ret && attachloop == 0)
2710 SV_GetEntityMatrix(ent, &entitymatrix, false);
2711 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2712 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2713 // next iteration we process the parent entity
2714 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2716 tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
2717 ent = PRVM_EDICT_NUM(val->edict);
2724 // RENDER_VIEWMODEL magic
2725 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
2727 Matrix4x4_Copy(&tagmatrix, out);
2728 ent = PRVM_EDICT_NUM(val->edict);
2730 SV_GetEntityMatrix(ent, &entitymatrix, true);
2731 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2734 // Cl_bob, ported from rendering code
2735 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2738 // LordHavoc: this code is *weird*, but not replacable (I think it
2739 // should be done in QC on the server, but oh well, quake is quake)
2740 // LordHavoc: figured out bobup: the time at which the sin is at 180
2741 // degrees (which allows lengthening or squishing the peak or valley)
2742 cycle = sv.time/cl_bobcycle.value;
2743 cycle -= (int)cycle;
2744 if (cycle < cl_bobup.value)
2745 cycle = sin(M_PI * cycle / cl_bobup.value);
2747 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2748 // bob is proportional to velocity in the xy plane
2749 // (don't count Z, or jumping messes it up)
2750 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;
2751 bob = bob*0.3 + bob*0.7*cycle;
2752 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2759 //float(entity ent, string tagname) gettagindex;
2761 static void VM_SV_gettagindex (void)
2764 const char *tag_name;
2767 VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
2769 ent = PRVM_G_EDICT(OFS_PARM0);
2770 tag_name = PRVM_G_STRING(OFS_PARM1);
2772 if (ent == prog->edicts)
2774 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
2777 if (ent->priv.server->free)
2779 VM_Warning("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
2784 if (!SV_GetModelFromEdict(ent))
2785 Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2788 tag_index = SV_GetTagIndex(ent, tag_name);
2790 if(developer.integer >= 100)
2791 Con_Printf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2793 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2796 //vector(entity ent, float tagindex) gettaginfo;
2797 static void VM_SV_gettaginfo (void)
2801 matrix4x4_t tag_matrix;
2802 matrix4x4_t tag_localmatrix;
2804 const char *tagname;
2807 vec3_t fo, le, up, trans;
2808 const dp_model_t *model;
2810 VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
2812 e = PRVM_G_EDICT(OFS_PARM0);
2813 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2815 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2816 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2817 VectorScale(le, -1, prog->globals.server->v_right);
2818 model = SV_GetModelFromEdict(e);
2819 VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
2820 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
2821 VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
2822 SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
2823 Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
2825 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
2826 val->_float = parentindex;
2827 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
2828 val->string = tagname ? PRVM_SetTempString(tagname) : 0;
2829 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
2830 VectorCopy(trans, val->vector);
2831 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
2832 VectorCopy(fo, val->vector);
2833 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
2834 VectorScale(le, -1, val->vector);
2835 if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
2836 VectorCopy(up, val->vector);
2841 VM_Warning("gettagindex: can't affect world entity\n");
2844 VM_Warning("gettagindex: can't affect free entity\n");
2847 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2850 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2853 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2858 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2859 static void VM_SV_dropclient (void)
2862 client_t *oldhostclient;
2863 VM_SAFEPARMCOUNT(1, VM_SV_dropclient);
2864 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2865 if (clientnum < 0 || clientnum >= svs.maxclients)
2867 VM_Warning("dropclient: not a client\n");
2870 if (!svs.clients[clientnum].active)
2872 VM_Warning("dropclient: that client slot is not connected\n");
2875 oldhostclient = host_client;
2876 host_client = svs.clients + clientnum;
2877 SV_DropClient(false);
2878 host_client = oldhostclient;
2881 //entity() spawnclient (DP_SV_BOTCLIENT)
2882 static void VM_SV_spawnclient (void)
2886 VM_SAFEPARMCOUNT(0, VM_SV_spawnclient);
2887 prog->xfunction->builtinsprofile += 2;
2889 for (i = 0;i < svs.maxclients;i++)
2891 if (!svs.clients[i].active)
2893 prog->xfunction->builtinsprofile += 100;
2894 SV_ConnectClient (i, NULL);
2895 // this has to be set or else ClientDisconnect won't be called
2896 // we assume the qc will call ClientConnect...
2897 svs.clients[i].clientconnectcalled = true;
2898 ed = PRVM_EDICT_NUM(i + 1);
2902 VM_RETURN_EDICT(ed);
2905 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2906 static void VM_SV_clienttype (void)
2909 VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
2910 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2911 if (clientnum < 0 || clientnum >= svs.maxclients)
2912 PRVM_G_FLOAT(OFS_RETURN) = 3;
2913 else if (!svs.clients[clientnum].active)
2914 PRVM_G_FLOAT(OFS_RETURN) = 0;
2915 else if (svs.clients[clientnum].netconnection)
2916 PRVM_G_FLOAT(OFS_RETURN) = 1;
2918 PRVM_G_FLOAT(OFS_RETURN) = 2;
2925 string(string key) serverkey
2928 void VM_SV_serverkey(void)
2930 char string[VM_STRINGTEMP_LENGTH];
2931 VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
2932 InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2933 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2936 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2937 static void VM_SV_setmodelindex (void)
2942 VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
2944 e = PRVM_G_EDICT(OFS_PARM0);
2945 if (e == prog->edicts)
2947 VM_Warning("setmodelindex: can not modify world entity\n");
2950 if (e->priv.server->free)
2952 VM_Warning("setmodelindex: can not modify free entity\n");
2955 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2956 if (i <= 0 || i >= MAX_MODELS)
2958 VM_Warning("setmodelindex: invalid modelindex\n");
2961 if (!sv.model_precache[i][0])
2963 VM_Warning("setmodelindex: model not precached\n");
2967 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
2968 e->fields.server->modelindex = i;
2970 mod = SV_GetModelByIndex(i);
2974 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
2975 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
2977 SetMinMaxSize (e, quakemins, quakemaxs, true);
2980 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
2983 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2984 static void VM_SV_modelnameforindex (void)
2987 VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
2989 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2991 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2992 if (i <= 0 || i >= MAX_MODELS)
2994 VM_Warning("modelnameforindex: invalid modelindex\n");
2997 if (!sv.model_precache[i][0])
2999 VM_Warning("modelnameforindex: model not precached\n");
3003 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
3006 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
3007 static void VM_SV_particleeffectnum (void)
3010 VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
3011 i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0));
3014 PRVM_G_FLOAT(OFS_RETURN) = i;
3017 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3018 static void VM_SV_trailparticles (void)
3020 VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
3022 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3025 MSG_WriteByte(&sv.datagram, svc_trailparticles);
3026 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
3027 MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
3028 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
3029 MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
3030 SV_FlushBroadcastMessages();
3033 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
3034 static void VM_SV_pointparticles (void)
3036 int effectnum, count;
3038 VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
3040 if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
3043 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
3044 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
3045 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
3046 count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
3047 if (count == 1 && !VectorLength2(vel))
3050 MSG_WriteByte(&sv.datagram, svc_pointparticles1);
3051 MSG_WriteShort(&sv.datagram, effectnum);
3052 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3056 // 1+2+12+12+2=29 bytes
3057 MSG_WriteByte(&sv.datagram, svc_pointparticles);
3058 MSG_WriteShort(&sv.datagram, effectnum);
3059 MSG_WriteVector(&sv.datagram, org, sv.protocol);
3060 MSG_WriteVector(&sv.datagram, vel, sv.protocol);
3061 MSG_WriteShort(&sv.datagram, count);
3064 SV_FlushBroadcastMessages();
3067 //PF_setpause, // void(float pause) setpause = #531;
3068 static void VM_SV_setpause(void) {
3070 pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
3071 if (pauseValue != 0) { //pause the game
3073 sv.pausedstart = Sys_DoubleTime();
3074 } else { //disable pause, in case it was enabled
3075 if (sv.paused != 0) {
3080 // send notification to all clients
3081 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
3082 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
3085 // #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.
3086 static void VM_SV_skel_create(void)
3088 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3089 dp_model_t *model = SV_GetModelByIndex(modelindex);
3090 skeleton_t *skeleton;
3092 PRVM_G_FLOAT(OFS_RETURN) = 0;
3093 if (!model || !model->num_bones)
3095 for (i = 0;i < MAX_EDICTS;i++)
3096 if (!prog->skeletons[i])
3098 if (i == MAX_EDICTS)
3100 prog->skeletons[i] = skeleton = Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
3101 skeleton->model = model;
3102 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
3103 // initialize to identity matrices
3104 for (i = 0;i < skeleton->model->num_bones;i++)
3105 skeleton->relativetransforms[i] = identitymatrix;
3106 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
3109 // #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
3110 static void VM_SV_skel_build(void)
3112 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3113 skeleton_t *skeleton;
3114 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
3115 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
3116 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
3117 int firstbone = PRVM_G_FLOAT(OFS_PARM4);
3118 int lastbone = PRVM_G_FLOAT(OFS_PARM5);
3119 dp_model_t *model = SV_GetModelByIndex(modelindex);
3124 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
3125 frameblend_t frameblend[MAX_FRAMEBLENDS];
3126 matrix4x4_t blendedmatrix;
3128 PRVM_G_FLOAT(OFS_RETURN) = 0;
3129 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3131 firstbone = max(0, firstbone);
3132 lastbone = min(lastbone, model->num_bones - 1);
3133 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3134 VM_GenerateFrameGroupBlend(framegroupblend, ed);
3135 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
3136 blendfrac = 1.0f - retainfrac;
3137 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
3138 frameblend[numblends].lerp *= blendfrac;
3139 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3141 memset(&blendedmatrix, 0, sizeof(blendedmatrix));
3142 Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
3143 for (blendindex = 0;blendindex < numblends;blendindex++)
3145 Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
3146 Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
3148 skeleton->relativetransforms[bonenum] = blendedmatrix;
3150 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex;
3153 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3154 static void VM_SV_skel_get_numbones(void)
3156 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3157 skeleton_t *skeleton;
3158 PRVM_G_FLOAT(OFS_RETURN) = 0;
3159 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3161 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
3164 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
3165 static void VM_SV_skel_get_bonename(void)
3167 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3168 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3169 skeleton_t *skeleton;
3170 PRVM_G_INT(OFS_RETURN) = 0;
3171 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3173 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3175 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
3178 // #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)
3179 static void VM_SV_skel_get_boneparent(void)
3181 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3182 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3183 skeleton_t *skeleton;
3184 PRVM_G_FLOAT(OFS_RETURN) = 0;
3185 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3187 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3189 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
3192 // #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
3193 static void VM_SV_skel_find_bone(void)
3195 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3196 const char *tagname = PRVM_G_STRING(OFS_PARM1);
3197 skeleton_t *skeleton;
3198 PRVM_G_FLOAT(OFS_RETURN) = 0;
3199 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3201 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
3204 // #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)
3205 static void VM_SV_skel_get_bonerel(void)
3207 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3208 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3209 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 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3222 VectorCopy(forward, prog->globals.client->v_forward);
3223 VectorNegate(left, prog->globals.client->v_right);
3224 VectorCopy(up, prog->globals.client->v_up);
3225 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3228 // #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)
3229 static void VM_SV_skel_get_boneabs(void)
3231 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3232 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3233 skeleton_t *skeleton;
3236 vec3_t forward, left, up, origin;
3237 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
3238 VectorClear(prog->globals.client->v_forward);
3239 VectorClear(prog->globals.client->v_right);
3240 VectorClear(prog->globals.client->v_up);
3241 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3243 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3245 matrix = skeleton->relativetransforms[bonenum];
3246 // convert to absolute
3247 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
3250 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
3252 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
3253 VectorCopy(forward, prog->globals.client->v_forward);
3254 VectorNegate(left, prog->globals.client->v_right);
3255 VectorCopy(up, prog->globals.client->v_up);
3256 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3259 // #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)
3260 static void VM_SV_skel_set_bone(void)
3262 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3263 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3264 vec3_t forward, left, up, origin;
3265 skeleton_t *skeleton;
3267 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3269 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3271 VectorCopy(prog->globals.client->v_forward, forward);
3272 VectorNegate(prog->globals.client->v_right, left);
3273 VectorCopy(prog->globals.client->v_up, up);
3274 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3275 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3276 skeleton->relativetransforms[bonenum] = matrix;
3279 // #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)
3280 static void VM_SV_skel_mul_bone(void)
3282 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3283 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3284 vec3_t forward, left, up, origin;
3285 skeleton_t *skeleton;
3288 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3290 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
3292 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
3293 VectorCopy(prog->globals.client->v_forward, forward);
3294 VectorNegate(prog->globals.client->v_right, left);
3295 VectorCopy(prog->globals.client->v_up, up);
3296 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3297 temp = skeleton->relativetransforms[bonenum];
3298 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3301 // #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)
3302 static void VM_SV_skel_mul_bones(void)
3304 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3305 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
3306 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3308 vec3_t forward, left, up, origin;
3309 skeleton_t *skeleton;
3312 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3314 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
3315 VectorCopy(prog->globals.client->v_forward, forward);
3316 VectorNegate(prog->globals.client->v_right, left);
3317 VectorCopy(prog->globals.client->v_up, up);
3318 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
3319 firstbone = max(0, firstbone);
3320 lastbone = min(lastbone, skeleton->model->num_bones - 1);
3321 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3323 temp = skeleton->relativetransforms[bonenum];
3324 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
3328 // #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
3329 static void VM_SV_skel_copybones(void)
3331 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3332 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
3333 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
3334 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
3336 skeleton_t *skeletondst;
3337 skeleton_t *skeletonsrc;
3338 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
3340 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
3342 firstbone = max(0, firstbone);
3343 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
3344 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
3345 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
3346 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
3349 // #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)
3350 static void VM_SV_skel_delete(void)
3352 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
3353 skeleton_t *skeleton;
3354 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
3357 prog->skeletons[skeletonindex] = NULL;
3360 // #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
3361 static void VM_SV_frameforname(void)
3363 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3364 dp_model_t *model = SV_GetModelByIndex(modelindex);
3365 const char *name = PRVM_G_STRING(OFS_PARM1);
3367 PRVM_G_FLOAT(OFS_RETURN) = -1;
3368 if (!model || !model->animscenes)
3370 for (i = 0;i < model->numframes;i++)
3372 if (!strcasecmp(model->animscenes[i].name, name))
3374 PRVM_G_FLOAT(OFS_RETURN) = i;
3380 // #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.
3381 static void VM_SV_frameduration(void)
3383 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
3384 dp_model_t *model = SV_GetModelByIndex(modelindex);
3385 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3386 PRVM_G_FLOAT(OFS_RETURN) = 0;
3387 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
3389 if (model->animscenes[framenum].framerate)
3390 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
3394 prvm_builtin_t vm_sv_builtins[] = {
3395 NULL, // #0 NULL function (not callable) (QUAKE)
3396 VM_makevectors, // #1 void(vector ang) makevectors (QUAKE)
3397 VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
3398 VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
3399 VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
3400 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
3401 VM_break, // #6 void() break (QUAKE)
3402 VM_random, // #7 float() random (QUAKE)
3403 VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
3404 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
3405 VM_error, // #10 void(string e) error (QUAKE)
3406 VM_objerror, // #11 void(string e) objerror (QUAKE)
3407 VM_vlen, // #12 float(vector v) vlen (QUAKE)
3408 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
3409 VM_spawn, // #14 entity() spawn (QUAKE)
3410 VM_remove, // #15 void(entity e) remove (QUAKE)
3411 VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
3412 VM_SV_checkclient, // #17 entity() checkclient (QUAKE)
3413 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
3414 VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE)
3415 VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE)
3416 VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
3417 VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
3418 VM_bprint, // #23 void(string s, ...) bprint (QUAKE)
3419 VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE)
3420 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
3421 VM_ftos, // #26 string(float f) ftos (QUAKE)
3422 VM_vtos, // #27 string(vector v) vtos (QUAKE)
3423 VM_coredump, // #28 void() coredump (QUAKE)
3424 VM_traceon, // #29 void() traceon (QUAKE)
3425 VM_traceoff, // #30 void() traceoff (QUAKE)
3426 VM_eprint, // #31 void(entity e) eprint (QUAKE)
3427 VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
3428 NULL, // #33 (QUAKE)
3429 VM_SV_droptofloor, // #34 float() droptofloor (QUAKE)
3430 VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
3431 VM_rint, // #36 float(float v) rint (QUAKE)
3432 VM_floor, // #37 float(float v) floor (QUAKE)
3433 VM_ceil, // #38 float(float v) ceil (QUAKE)
3434 NULL, // #39 (QUAKE)
3435 VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
3436 VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
3437 NULL, // #42 (QUAKE)
3438 VM_fabs, // #43 float(float f) fabs (QUAKE)
3439 VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE)
3440 VM_cvar, // #45 float(string s) cvar (QUAKE)
3441 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
3442 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
3443 VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
3444 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
3445 NULL, // #50 (QUAKE)
3446 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
3447 VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE)
3448 VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE)
3449 VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE)
3450 VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE)
3451 VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE)
3452 VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE)
3453 VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE)
3454 VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE)
3455 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE)
3456 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE)
3457 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE)
3458 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE)
3459 VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
3460 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
3461 NULL, // #66 (QUAKE)
3462 SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE)
3463 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
3464 VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE)
3465 VM_changelevel, // #70 void(string s) changelevel (QUAKE)
3466 NULL, // #71 (QUAKE)
3467 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
3468 VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE)
3469 VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
3470 VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE)
3471 VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
3472 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
3473 VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE)
3474 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
3475 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
3476 VM_stof, // #81 float(string s) stof (FRIK_FILE)
3477 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
3478 NULL, // #83 (QUAKE)
3479 NULL, // #84 (QUAKE)
3480 NULL, // #85 (QUAKE)
3481 NULL, // #86 (QUAKE)
3482 NULL, // #87 (QUAKE)
3483 NULL, // #88 (QUAKE)
3484 NULL, // #89 (QUAKE)
3485 VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3486 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3487 VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3488 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3489 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3490 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3491 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3492 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3493 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3494 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3495 // FrikaC and Telejano range #100-#199
3506 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3507 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3508 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3509 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3510 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
3511 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
3512 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3513 VM_stov, // #117 vector(string) stov (FRIK_FILE)
3514 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
3515 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3596 // FTEQW range #200-#299
3615 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3618 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3619 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3620 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3621 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3622 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3623 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3624 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3625 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3626 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3627 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3629 VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3637 VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs;
3660 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.
3661 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
3662 VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
3663 VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
3664 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)
3665 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
3666 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)
3667 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)
3668 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)
3669 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)
3670 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)
3671 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
3672 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)
3673 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
3674 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.
3697 // CSQC range #300-#399
3698 NULL, // #300 void() clearscene (EXT_CSQC)
3699 NULL, // #301 void(float mask) addentities (EXT_CSQC)
3700 NULL, // #302 void(entity ent) addentity (EXT_CSQC)
3701 NULL, // #303 float(float property, ...) setproperty (EXT_CSQC)
3702 NULL, // #304 void() renderscene (EXT_CSQC)
3703 NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3704 NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3705 NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3706 NULL, // #308 void() R_EndPolygon
3708 NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3709 NULL, // #311 vector (vector v) cs_project (EXT_CSQC)
3713 NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3714 NULL, // #316 float(string name) iscachedpic (EXT_CSQC)
3715 NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3716 NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3717 NULL, // #319 void(string name) freepic (EXT_CSQC)
3718 NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3719 NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3720 NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3721 NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3722 NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea
3723 NULL, // #325 void(void) drawresetcliparea
3728 NULL, // #330 float(float stnum) getstatf (EXT_CSQC)
3729 NULL, // #331 float(float stnum) getstati (EXT_CSQC)
3730 NULL, // #332 string(float firststnum) getstats (EXT_CSQC)
3731 VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3732 VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3733 VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3734 VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3735 VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3736 NULL, // #338 void(string s, ...) centerprint (EXT_CSQC)
3737 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3738 NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3739 NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3740 NULL, // #342 string(float keynum) getkeybind (EXT_CSQC)
3741 NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3742 NULL, // #344 vector() getmousepos (EXT_CSQC)
3743 NULL, // #345 float(float framenum) getinputstate (EXT_CSQC)
3744 NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3745 NULL, // #347 void() runstandardplayerphysics (EXT_CSQC)
3746 NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3747 NULL, // #349 float() isdemo (EXT_CSQC)
3748 VM_isserver, // #350 float() isserver (EXT_CSQC)
3749 NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3750 NULL, // #352 void(string cmdname) registercommand (EXT_CSQC)
3751 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3752 VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3758 NULL, // #360 float() readbyte (EXT_CSQC)
3759 NULL, // #361 float() readchar (EXT_CSQC)
3760 NULL, // #362 float() readshort (EXT_CSQC)
3761 NULL, // #363 float() readlong (EXT_CSQC)
3762 NULL, // #364 float() readcoord (EXT_CSQC)
3763 NULL, // #365 float() readangle (EXT_CSQC)
3764 NULL, // #366 string() readstring (EXT_CSQC)
3765 NULL, // #367 float() readfloat (EXT_CSQC)
3798 // LordHavoc's range #400-#499
3799 VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3800 VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3801 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3802 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3803 VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3804 VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3805 VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3806 VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3807 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)
3808 VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3809 VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3810 VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3811 VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3812 VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3813 VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3814 VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3815 VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3816 VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3817 VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3818 VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3819 VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3820 VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3821 VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3822 VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3823 VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3824 VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3825 VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3826 VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3827 VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3828 VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3829 VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3830 VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3831 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3832 VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3833 VM_SV_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3834 VM_SV_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3835 VM_SV_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3836 VM_SV_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3837 VM_SV_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3838 VM_SV_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3839 VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3840 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3841 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3842 VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3843 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3844 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3845 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3846 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3847 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3848 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3849 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3850 VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3851 VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3852 VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3853 VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3854 VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3855 VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3856 VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3858 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3859 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3860 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3861 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3862 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3863 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3864 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3865 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3866 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3867 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3868 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3870 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3871 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3872 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3873 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3874 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3875 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3876 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
3877 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3878 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3879 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3880 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3881 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3882 VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
3883 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3884 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3885 VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
3893 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3894 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
3895 VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA)
3896 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
3897 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
3898 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
3899 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
3900 VM_SV_WritePicture, // #501
3902 VM_whichpack, // #503 string(string) whichpack = #503;
3909 VM_uri_escape, // #510 string(string in) uri_escape = #510;
3910 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
3911 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
3912 VM_uri_get, // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
3913 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
3914 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
3915 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
3916 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
3917 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
3918 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
3928 VM_loadfromdata, // #529
3929 VM_loadfromfile, // #530
3930 VM_SV_setpause, // #531 void(float pause) setpause = #531;
4004 VM_callfunction, // #605
4005 VM_writetofile, // #606
4006 VM_isfunction, // #607
4012 VM_parseentitydata, // #613
4023 VM_SV_getextresponse, // #624 string getextresponse(void)
4027 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
4029 void VM_SV_Cmd_Init(void)
4034 void VM_SV_Cmd_Reset(void)
4036 World_End(&sv.world);
4037 if(prog->funcoffsets.SV_Shutdown)
4039 func_t s = prog->funcoffsets.SV_Shutdown;
4040 prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
4041 PRVM_ExecuteProgram(s,"SV_Shutdown() required");