3 //============================================================================
6 #define PF_WARNING(s) do{Con_Printf(s);PRVM_PrintState();return;}while(0)
7 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
10 char *vm_sv_extensions =
12 "DP_CON_ALIASPARAMETERS "
30 "DP_ENT_CUSTOMCOLORMAP "
31 "DP_ENT_EXTERIORMODELTOCLIENT "
33 "DP_ENT_LOWPRECISION "
36 "DP_GFX_EXTERNALTEXTURES "
38 "DP_GFX_QUAKE3MODELTAGS "
42 "DP_HALFLIFE_MAP_CVAR "
48 "DP_MOVETYPEBOUNCEMISSILE "
55 "DP_QC_FINDCHAINFLAGS "
56 "DP_QC_FINDCHAINFLOAT "
59 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
64 "DP_QC_MULTIPLETEMPSTRINGS "
66 "DP_QC_SINCOSSQRTPOW "
69 "DP_QC_TRACE_MOVETYPE_HITMODEL "
70 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
71 "DP_QC_VECTORVECTORS "
77 "DP_SND_DIRECTIONLESSATTNNONE "
86 "DP_SV_DRAWONLYTOCLIENT "
89 "DP_SV_NODRAWTOCLIENT "
91 "DP_SV_PLAYERPHYSICS "
92 "DP_SV_PRECACHEANYTIME "
94 "DP_SV_ROTATINGBMODEL "
97 "DP_SV_WRITEUNTERMINATEDSTRING "
101 "DP_TE_EXPLOSIONRGB "
103 "DP_TE_PARTICLECUBE "
104 "DP_TE_PARTICLERAIN "
105 "DP_TE_PARTICLESNOW "
107 "DP_TE_QUADEFFECTS1 "
110 "DP_TE_STANDARDEFFECTBUILTINS "
113 "KRIMZON_SV_PARSECLIENTCOMMAND "
117 "PRYDON_CLIENTCURSOR "
118 "TENEBRAE_GFX_DLIGHTS "
120 "NEXUIZ_PLAYERMODEL "
127 Writes new values for v_forward, v_up, and v_right based on angles
131 void PF_makevectors (void)
133 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
140 Writes new values for v_forward, v_up, and v_right based on the given forward vector
141 vectorvectors(vector, vector)
144 void PF_vectorvectors (void)
146 VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward);
147 VectorVectors(prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
154 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.
156 setorigin (entity, origin)
159 void PF_setorigin (void)
164 e = PRVM_G_EDICT(OFS_PARM0);
165 if (e == prog->edicts)
166 PF_WARNING("setorigin: can not modify world entity\n");
167 if (e->priv.server->free)
168 PF_WARNING("setorigin: can not modify free entity\n");
169 org = PRVM_G_VECTOR(OFS_PARM1);
170 VectorCopy (org, e->fields.server->origin);
171 SV_LinkEdict (e, false);
175 void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
179 for (i=0 ; i<3 ; i++)
181 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
183 // set derived values
184 VectorCopy (min, e->fields.server->mins);
185 VectorCopy (max, e->fields.server->maxs);
186 VectorSubtract (max, min, e->fields.server->size);
188 SV_LinkEdict (e, false);
195 the size box is rotated by the current angle
196 LordHavoc: no it isn't...
198 setsize (entity, minvector, maxvector)
201 void PF_setsize (void)
206 e = PRVM_G_EDICT(OFS_PARM0);
207 if (e == prog->edicts)
208 PF_WARNING("setsize: can not modify world entity\n");
209 if (e->priv.server->free)
210 PF_WARNING("setsize: can not modify free entity\n");
211 min = PRVM_G_VECTOR(OFS_PARM1);
212 max = PRVM_G_VECTOR(OFS_PARM2);
213 SetMinMaxSize (e, min, max, false);
221 setmodel(entity, model)
224 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
225 void PF_setmodel (void)
231 e = PRVM_G_EDICT(OFS_PARM0);
232 if (e == prog->edicts)
233 PF_WARNING("setmodel: can not modify world entity\n");
234 if (e->priv.server->free)
235 PF_WARNING("setmodel: can not modify free entity\n");
236 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
237 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
238 e->fields.server->modelindex = i;
244 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
245 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
247 SetMinMaxSize (e, quakemins, quakemaxs, true);
250 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
257 single print to a specific client
259 sprint(clientent, value)
262 void PF_sprint (void)
266 char string[VM_STRINGTEMP_LENGTH];
268 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
270 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
272 Con_Print("tried to sprint to a non-client\n");
276 client = svs.clients + entnum-1;
277 VM_VarString(1, string, sizeof(string));
278 MSG_WriteChar(&client->message,svc_print);
279 MSG_WriteString(&client->message, string);
287 single print to a specific client
289 centerprint(clientent, value)
292 void PF_centerprint (void)
296 char string[VM_STRINGTEMP_LENGTH];
298 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
300 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
302 Con_Print("tried to sprint to a non-client\n");
306 client = svs.clients + entnum-1;
307 VM_VarString(1, string, sizeof(string));
308 MSG_WriteChar(&client->message,svc_centerprint);
309 MSG_WriteString(&client->message, string);
316 particle(origin, color, count)
319 void PF_particle (void)
325 org = PRVM_G_VECTOR(OFS_PARM0);
326 dir = PRVM_G_VECTOR(OFS_PARM1);
327 color = PRVM_G_FLOAT(OFS_PARM2);
328 count = PRVM_G_FLOAT(OFS_PARM3);
329 SV_StartParticle (org, dir, color, count);
339 void PF_ambientsound (void)
343 float vol, attenuation;
346 pos = PRVM_G_VECTOR (OFS_PARM0);
347 samp = PRVM_G_STRING(OFS_PARM1);
348 vol = PRVM_G_FLOAT(OFS_PARM2);
349 attenuation = PRVM_G_FLOAT(OFS_PARM3);
351 // check to see if samp was properly precached
352 soundnum = SV_SoundIndex(samp, 1);
360 // add an svc_spawnambient command to the level signon packet
363 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
365 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
367 MSG_WriteVector(&sv.signon, pos, sv.protocol);
370 MSG_WriteShort (&sv.signon, soundnum);
372 MSG_WriteByte (&sv.signon, soundnum);
374 MSG_WriteByte (&sv.signon, vol*255);
375 MSG_WriteByte (&sv.signon, attenuation*64);
383 Each entity can have eight independant sound sources, like voice,
386 Channel 0 is an auto-allocate channel, the others override anything
387 already running on that entity/channel pair.
389 An attenuation of 0 will play full volume everywhere in the level.
390 Larger attenuations will drop off.
398 prvm_edict_t *entity;
402 entity = PRVM_G_EDICT(OFS_PARM0);
403 channel = PRVM_G_FLOAT(OFS_PARM1);
404 sample = PRVM_G_STRING(OFS_PARM2);
405 volume = PRVM_G_FLOAT(OFS_PARM3) * 255;
406 attenuation = PRVM_G_FLOAT(OFS_PARM4);
408 if (volume < 0 || volume > 255)
409 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
411 if (attenuation < 0 || attenuation > 4)
412 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
414 if (channel < 0 || channel > 7)
415 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
417 SV_StartSound (entity, channel, sample, volume, attenuation);
424 Used for use tracing and shot targeting
425 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
426 if the tryents flag is set.
428 traceline (vector1, vector2, tryents)
431 void PF_traceline (void)
438 prog->xfunction->builtinsprofile += 30;
440 v1 = PRVM_G_VECTOR(OFS_PARM0);
441 v2 = PRVM_G_VECTOR(OFS_PARM1);
442 move = PRVM_G_FLOAT(OFS_PARM2);
443 ent = PRVM_G_EDICT(OFS_PARM3);
445 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
447 prog->globals.server->trace_allsolid = trace.allsolid;
448 prog->globals.server->trace_startsolid = trace.startsolid;
449 prog->globals.server->trace_fraction = trace.fraction;
450 prog->globals.server->trace_inwater = trace.inwater;
451 prog->globals.server->trace_inopen = trace.inopen;
452 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
453 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
454 prog->globals.server->trace_plane_dist = trace.plane.dist;
456 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
458 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
459 // FIXME: add trace_endcontents
467 Used for use tracing and shot targeting
468 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
469 if the tryents flag is set.
471 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
474 // LordHavoc: added this for my own use, VERY useful, similar to traceline
475 void PF_tracebox (void)
477 float *v1, *v2, *m1, *m2;
482 prog->xfunction->builtinsprofile += 30;
484 v1 = PRVM_G_VECTOR(OFS_PARM0);
485 m1 = PRVM_G_VECTOR(OFS_PARM1);
486 m2 = PRVM_G_VECTOR(OFS_PARM2);
487 v2 = PRVM_G_VECTOR(OFS_PARM3);
488 move = PRVM_G_FLOAT(OFS_PARM4);
489 ent = PRVM_G_EDICT(OFS_PARM5);
491 trace = SV_Move (v1, m1, m2, v2, move, ent);
493 prog->globals.server->trace_allsolid = trace.allsolid;
494 prog->globals.server->trace_startsolid = trace.startsolid;
495 prog->globals.server->trace_fraction = trace.fraction;
496 prog->globals.server->trace_inwater = trace.inwater;
497 prog->globals.server->trace_inopen = trace.inopen;
498 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
499 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
500 prog->globals.server->trace_plane_dist = trace.plane.dist;
502 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
504 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
507 extern trace_t SV_Trace_Toss (prvm_edict_t *ent, prvm_edict_t *ignore);
508 void PF_tracetoss (void)
512 prvm_edict_t *ignore;
514 prog->xfunction->builtinsprofile += 600;
516 ent = PRVM_G_EDICT(OFS_PARM0);
517 if (ent == prog->edicts)
518 PF_WARNING("tracetoss: can not use world entity\n");
519 ignore = PRVM_G_EDICT(OFS_PARM1);
521 trace = SV_Trace_Toss (ent, ignore);
523 prog->globals.server->trace_allsolid = trace.allsolid;
524 prog->globals.server->trace_startsolid = trace.startsolid;
525 prog->globals.server->trace_fraction = trace.fraction;
526 prog->globals.server->trace_inwater = trace.inwater;
527 prog->globals.server->trace_inopen = trace.inopen;
528 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
529 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
530 prog->globals.server->trace_plane_dist = trace.plane.dist;
532 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
534 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
542 Returns true if the given entity can move to the given position from it's
543 current position by walking or rolling.
545 scalar checkpos (entity, vector)
548 void PF_checkpos (void)
552 //============================================================================
555 unsigned char checkpvs[MAX_MAP_LEAFS/8];
557 int PF_newcheckclient (int check)
563 // cycle to the next one
565 check = bound(1, check, svs.maxclients);
566 if (check == svs.maxclients)
574 prog->xfunction->builtinsprofile++;
576 if (i == svs.maxclients+1)
578 // look up the client's edict
579 ent = PRVM_EDICT_NUM(i);
580 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
581 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
583 // found a valid client (possibly the same one again)
587 // get the PVS for the entity
588 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
590 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
591 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
600 Returns a client (or object that has a client enemy) that would be a
603 If there is more than one valid option, they are cycled each frame
605 If (self.origin + self.viewofs) is not in the PVS of the current target,
606 it is not returned at all.
611 int c_invis, c_notvis;
612 void PF_checkclient (void)
614 prvm_edict_t *ent, *self;
617 // find a new check if on a new frame
618 if (sv.time - sv.lastchecktime >= 0.1)
620 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
621 sv.lastchecktime = sv.time;
624 // return check if it might be visible
625 ent = PRVM_EDICT_NUM(sv.lastcheck);
626 if (ent->priv.server->free || ent->fields.server->health <= 0)
628 VM_RETURN_EDICT(prog->edicts);
632 // if current entity can't possibly see the check entity, return 0
633 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
634 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
635 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
638 VM_RETURN_EDICT(prog->edicts);
642 // might be able to see it
644 VM_RETURN_EDICT(ent);
647 //============================================================================
654 Sends text over to the client's execution buffer
656 stuffcmd (clientent, value, ...)
659 void PF_stuffcmd (void)
663 char string[VM_STRINGTEMP_LENGTH];
665 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
666 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
668 Con_Print("Can't stuffcmd to a non-client\n");
672 VM_VarString(1, string, sizeof(string));
675 host_client = svs.clients + entnum-1;
676 Host_ClientCommands ("%s", string);
684 Returns a chain of entities that have origins within a spherical area
686 findradius (origin, radius)
689 void PF_findradius (void)
691 prvm_edict_t *ent, *chain;
692 vec_t radius, radius2;
693 vec3_t org, eorg, mins, maxs;
696 prvm_edict_t *touchedicts[MAX_EDICTS];
698 chain = (prvm_edict_t *)prog->edicts;
700 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
701 radius = PRVM_G_FLOAT(OFS_PARM1);
702 radius2 = radius * radius;
704 mins[0] = org[0] - (radius + 1);
705 mins[1] = org[1] - (radius + 1);
706 mins[2] = org[2] - (radius + 1);
707 maxs[0] = org[0] + (radius + 1);
708 maxs[1] = org[1] + (radius + 1);
709 maxs[2] = org[2] + (radius + 1);
710 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
711 if (numtouchedicts > MAX_EDICTS)
713 // this never happens
714 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
715 numtouchedicts = MAX_EDICTS;
717 for (i = 0;i < numtouchedicts;i++)
719 ent = touchedicts[i];
720 prog->xfunction->builtinsprofile++;
721 // Quake did not return non-solid entities but darkplaces does
722 // (note: this is the reason you can't blow up fallen zombies)
723 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
725 // LordHavoc: compare against bounding box rather than center so it
726 // doesn't miss large objects, and use DotProduct instead of Length
727 // for a major speedup
728 VectorSubtract(org, ent->fields.server->origin, eorg);
729 if (sv_gameplayfix_findradiusdistancetobox.integer)
731 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
732 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
733 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
736 VectorMAMAM(1, eorg, 0.5f, ent->fields.server->mins, 0.5f, ent->fields.server->maxs, eorg);
737 if (DotProduct(eorg, eorg) < radius2)
739 ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
744 VM_RETURN_EDICT(chain);
747 void PF_precache_file (void)
748 { // precache_file is only used to copy files with qcc, it does nothing
749 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
753 void PF_precache_sound (void)
755 SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
756 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
759 void PF_precache_model (void)
761 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
762 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
769 float(float yaw, float dist) walkmove
772 void PF_walkmove (void)
780 // assume failure if it returns early
781 PRVM_G_FLOAT(OFS_RETURN) = 0;
783 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
784 if (ent == prog->edicts)
785 PF_WARNING("walkmove: can not modify world entity\n");
786 if (ent->priv.server->free)
787 PF_WARNING("walkmove: can not modify free entity\n");
788 yaw = PRVM_G_FLOAT(OFS_PARM0);
789 dist = PRVM_G_FLOAT(OFS_PARM1);
791 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
794 yaw = yaw*M_PI*2 / 360;
796 move[0] = cos(yaw)*dist;
797 move[1] = sin(yaw)*dist;
800 // save program state, because SV_movestep may call other progs
801 oldf = prog->xfunction;
802 oldself = prog->globals.server->self;
804 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
807 // restore program state
808 prog->xfunction = oldf;
809 prog->globals.server->self = oldself;
819 void PF_droptofloor (void)
825 // assume failure if it returns early
826 PRVM_G_FLOAT(OFS_RETURN) = 0;
828 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
829 if (ent == prog->edicts)
830 PF_WARNING("droptofloor: can not modify world entity\n");
831 if (ent->priv.server->free)
832 PF_WARNING("droptofloor: can not modify free entity\n");
834 VectorCopy (ent->fields.server->origin, end);
837 trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent);
839 if (trace.fraction != 1)
841 VectorCopy (trace.endpos, ent->fields.server->origin);
842 SV_LinkEdict (ent, false);
843 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
844 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
845 PRVM_G_FLOAT(OFS_RETURN) = 1;
846 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
847 ent->priv.server->suspendedinairflag = true;
855 void(float style, string value) lightstyle
858 void PF_lightstyle (void)
865 style = PRVM_G_FLOAT(OFS_PARM0);
866 val = PRVM_G_STRING(OFS_PARM1);
868 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
869 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
872 // change the string in sv
873 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
875 // send message to all clients on this server
876 if (sv.state != ss_active)
879 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
883 MSG_WriteChar (&client->message, svc_lightstyle);
884 MSG_WriteChar (&client->message,style);
885 MSG_WriteString (&client->message, val);
895 void PF_checkbottom (void)
897 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
905 void PF_pointcontents (void)
907 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
914 Pick a vector for the player to shoot along
915 vector aim(entity, missilespeed)
920 prvm_edict_t *ent, *check, *bestent;
921 vec3_t start, dir, end, bestdir;
924 float dist, bestdist;
927 // assume failure if it returns early
928 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
929 // if sv_aim is so high it can't possibly accept anything, skip out early
930 if (sv_aim.value >= 1)
933 ent = PRVM_G_EDICT(OFS_PARM0);
934 if (ent == prog->edicts)
935 PF_WARNING("aim: can not use world entity\n");
936 if (ent->priv.server->free)
937 PF_WARNING("aim: can not use free entity\n");
938 speed = PRVM_G_FLOAT(OFS_PARM1);
940 VectorCopy (ent->fields.server->origin, start);
943 // try sending a trace straight
944 VectorCopy (prog->globals.server->v_forward, dir);
945 VectorMA (start, 2048, dir, end);
946 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
947 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
948 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
950 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
955 // try all possible entities
956 VectorCopy (dir, bestdir);
957 bestdist = sv_aim.value;
960 check = PRVM_NEXT_EDICT(prog->edicts);
961 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
963 prog->xfunction->builtinsprofile++;
964 if (check->fields.server->takedamage != DAMAGE_AIM)
968 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
969 continue; // don't aim at teammate
970 for (j=0 ; j<3 ; j++)
971 end[j] = check->fields.server->origin[j]
972 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
973 VectorSubtract (end, start, dir);
974 VectorNormalize (dir);
975 dist = DotProduct (dir, prog->globals.server->v_forward);
977 continue; // to far to turn
978 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
980 { // can shoot at this one
988 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
989 dist = DotProduct (dir, prog->globals.server->v_forward);
990 VectorScale (prog->globals.server->v_forward, dist, end);
992 VectorNormalize (end);
993 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
997 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1005 This was a major timewaster in progs, so it was converted to C
1008 void PF_changeyaw (void)
1011 float ideal, current, move, speed;
1013 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1014 if (ent == prog->edicts)
1015 PF_WARNING("changeyaw: can not modify world entity\n");
1016 if (ent->priv.server->free)
1017 PF_WARNING("changeyaw: can not modify free entity\n");
1018 current = ANGLEMOD(ent->fields.server->angles[1]);
1019 ideal = ent->fields.server->ideal_yaw;
1020 speed = ent->fields.server->yaw_speed;
1022 if (current == ideal)
1024 move = ideal - current;
1025 if (ideal > current)
1046 ent->fields.server->angles[1] = ANGLEMOD (current + move);
1054 void PF_changepitch (void)
1057 float ideal, current, move, speed;
1060 ent = PRVM_G_EDICT(OFS_PARM0);
1061 if (ent == prog->edicts)
1062 PF_WARNING("changepitch: can not modify world entity\n");
1063 if (ent->priv.server->free)
1064 PF_WARNING("changepitch: can not modify free entity\n");
1065 current = ANGLEMOD( ent->fields.server->angles[0] );
1066 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1067 ideal = val->_float;
1070 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1073 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1074 speed = val->_float;
1077 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1081 if (current == ideal)
1083 move = ideal - current;
1084 if (ideal > current)
1105 ent->fields.server->angles[0] = ANGLEMOD (current + move);
1109 ===============================================================================
1113 ===============================================================================
1116 #define MSG_BROADCAST 0 // unreliable to all
1117 #define MSG_ONE 1 // reliable to one (msg_entity)
1118 #define MSG_ALL 2 // reliable to all
1119 #define MSG_INIT 3 // write to the init string
1121 sizebuf_t *WriteDest (void)
1127 dest = PRVM_G_FLOAT(OFS_PARM0);
1131 return &sv.datagram;
1134 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1135 entnum = PRVM_NUM_FOR_EDICT(ent);
1136 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1138 Con_Printf ("WriteDest: tried to write to non-client\n");
1139 return &sv.reliable_datagram;
1142 return &svs.clients[entnum-1].message;
1145 Con_Printf ("WriteDest: bad destination\n");
1147 return &sv.reliable_datagram;
1156 void PF_WriteByte (void)
1158 MSG_WriteByte (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1161 void PF_WriteChar (void)
1163 MSG_WriteChar (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1166 void PF_WriteShort (void)
1168 MSG_WriteShort (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1171 void PF_WriteLong (void)
1173 MSG_WriteLong (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1176 void PF_WriteAngle (void)
1178 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1181 void PF_WriteCoord (void)
1183 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1186 void PF_WriteString (void)
1188 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1191 void PF_WriteUnterminatedString (void)
1193 MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1197 void PF_WriteEntity (void)
1199 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1202 //////////////////////////////////////////////////////////
1204 void PF_makestatic (void)
1209 ent = PRVM_G_EDICT(OFS_PARM0);
1210 if (ent == prog->edicts)
1211 PF_WARNING("makestatic: can not modify world entity\n");
1212 if (ent->priv.server->free)
1213 PF_WARNING("makestatic: can not modify free entity\n");
1216 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1221 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1222 MSG_WriteShort (&sv.signon, ent->fields.server->modelindex);
1223 MSG_WriteShort (&sv.signon, ent->fields.server->frame);
1227 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1228 MSG_WriteByte (&sv.signon, ent->fields.server->modelindex);
1229 MSG_WriteByte (&sv.signon, ent->fields.server->frame);
1232 MSG_WriteByte (&sv.signon, ent->fields.server->colormap);
1233 MSG_WriteByte (&sv.signon, ent->fields.server->skin);
1234 for (i=0 ; i<3 ; i++)
1236 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1237 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1240 // throw the entity away now
1244 //=============================================================================
1251 void PF_setspawnparms (void)
1257 ent = PRVM_G_EDICT(OFS_PARM0);
1258 i = PRVM_NUM_FOR_EDICT(ent);
1259 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1261 Con_Print("tried to setspawnparms on a non-client\n");
1265 // copy spawn parms out of the client_t
1266 client = svs.clients + i-1;
1267 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1268 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1275 Returns a color vector indicating the lighting at the requested point.
1277 (Internal Operation note: actually measures the light beneath the point, just like
1278 the model lighting on the client)
1283 void PF_getlight (void)
1285 vec3_t ambientcolor, diffusecolor, diffusenormal;
1287 p = PRVM_G_VECTOR(OFS_PARM0);
1288 VectorClear(ambientcolor);
1289 VectorClear(diffusecolor);
1290 VectorClear(diffusenormal);
1291 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1292 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1293 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1296 void PF_registercvar (void)
1298 const char *name, *value;
1299 name = PRVM_G_STRING(OFS_PARM0);
1300 value = PRVM_G_STRING(OFS_PARM1);
1301 PRVM_G_FLOAT(OFS_RETURN) = 0;
1303 // first check to see if it has already been defined
1304 if (Cvar_FindVar (name))
1307 // check for overlap with a command
1308 if (Cmd_Exists (name))
1310 Con_Printf("PF_registercvar: %s is a command\n", name);
1314 Cvar_Get(name, value, 0);
1316 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1323 copies data from one entity to another
1325 copyentity(src, dst)
1328 void PF_copyentity (void)
1330 prvm_edict_t *in, *out;
1331 in = PRVM_G_EDICT(OFS_PARM0);
1332 if (in == prog->edicts)
1333 PF_WARNING("copyentity: can not read world entity\n");
1334 if (in->priv.server->free)
1335 PF_WARNING("copyentity: can not read free entity\n");
1336 out = PRVM_G_EDICT(OFS_PARM1);
1337 if (out == prog->edicts)
1338 PF_WARNING("copyentity: can not modify world entity\n");
1339 if (out->priv.server->free)
1340 PF_WARNING("copyentity: can not modify free entity\n");
1341 memcpy(out->fields.server, in->fields.server, prog->progs->entityfields * 4);
1349 sets the color of a client and broadcasts the update to all connected clients
1351 setcolor(clientent, value)
1354 void PF_setcolor (void)
1360 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1361 i = PRVM_G_FLOAT(OFS_PARM1);
1363 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1365 Con_Print("tried to setcolor a non-client\n");
1369 client = svs.clients + entnum-1;
1372 if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1374 client->edict->fields.server->team = (i & 15) + 1;
1377 if (client->old_colors != client->colors)
1379 client->old_colors = client->colors;
1380 // send notification to all clients
1381 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1382 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1383 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1391 effect(origin, modelname, startframe, framecount, framerate)
1394 void PF_effect (void)
1398 s = PRVM_G_STRING(OFS_PARM1);
1400 PF_WARNING("effect: no model specified\n");
1402 i = SV_ModelIndex(s, 1);
1404 PF_WARNING("effect: model not precached\n");
1405 SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
1408 void PF_te_blood (void)
1410 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1412 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1413 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1415 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1416 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1417 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1419 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1420 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1421 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1423 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1426 void PF_te_bloodshower (void)
1428 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1430 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1431 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1433 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1434 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1435 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1437 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1438 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1439 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1441 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1443 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1446 void PF_te_explosionrgb (void)
1448 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1449 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1451 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1452 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1453 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1455 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1456 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1457 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1460 void PF_te_particlecube (void)
1462 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1464 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1465 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1467 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1468 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1469 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1471 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1472 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1473 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1475 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1476 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1477 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1479 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1481 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1482 // gravity true/false
1483 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1485 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1488 void PF_te_particlerain (void)
1490 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1492 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1493 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1495 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1496 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1497 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1499 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1500 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1501 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1503 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1504 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1505 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1507 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1509 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1512 void PF_te_particlesnow (void)
1514 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1516 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1517 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1519 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1520 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1521 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1523 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1524 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1525 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1527 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1528 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1529 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1531 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1533 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1536 void PF_te_spark (void)
1538 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1540 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1541 MSG_WriteByte(&sv.datagram, TE_SPARK);
1543 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1544 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1545 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1547 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1548 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1549 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1551 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1554 void PF_te_gunshotquad (void)
1556 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1557 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1559 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1560 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1561 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1564 void PF_te_spikequad (void)
1566 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1567 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1569 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1570 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1571 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1574 void PF_te_superspikequad (void)
1576 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1577 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1579 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1580 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1581 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1584 void PF_te_explosionquad (void)
1586 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1587 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1589 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1590 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1591 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1594 void PF_te_smallflash (void)
1596 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1597 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1599 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1600 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1601 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1604 void PF_te_customflash (void)
1606 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
1608 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1609 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
1611 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1612 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1613 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1615 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
1617 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
1619 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
1620 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
1621 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
1624 void PF_te_gunshot (void)
1626 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1627 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
1629 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1630 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1631 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1634 void PF_te_spike (void)
1636 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1637 MSG_WriteByte(&sv.datagram, TE_SPIKE);
1639 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1640 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1641 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1644 void PF_te_superspike (void)
1646 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1647 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
1649 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1650 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1651 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1654 void PF_te_explosion (void)
1656 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1657 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
1659 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1660 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1661 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1664 void PF_te_tarexplosion (void)
1666 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1667 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
1669 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1670 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1671 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1674 void PF_te_wizspike (void)
1676 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1677 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
1679 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1680 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1681 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1684 void PF_te_knightspike (void)
1686 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1687 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
1689 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1690 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1691 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1694 void PF_te_lavasplash (void)
1696 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1697 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
1699 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1700 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1701 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1704 void PF_te_teleport (void)
1706 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1707 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
1709 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1710 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1711 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1714 void PF_te_explosion2 (void)
1716 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1717 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
1719 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1720 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1721 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1723 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM1));
1724 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
1727 void PF_te_lightning1 (void)
1729 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1730 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
1732 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1734 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1735 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1736 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1738 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1739 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1740 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1743 void PF_te_lightning2 (void)
1745 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1746 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
1748 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1750 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1751 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1752 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1754 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1755 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1756 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1759 void PF_te_lightning3 (void)
1761 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1762 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
1764 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1766 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1767 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1768 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1770 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1771 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1772 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1775 void PF_te_beam (void)
1777 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1778 MSG_WriteByte(&sv.datagram, TE_BEAM);
1780 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1782 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1783 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1784 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1786 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1787 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1788 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1791 void PF_te_plasmaburn (void)
1793 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1794 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
1795 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1796 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1797 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1800 void PF_te_flamejet (void)
1802 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1803 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
1805 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1806 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1807 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1809 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1810 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1811 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1813 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
1816 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
1819 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
1821 bestdist = 1000000000;
1823 for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
1825 // clip original point to each triangle of the surface and find the
1826 // triangle that is closest
1827 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
1828 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
1829 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
1830 TriangleNormal(v[0], v[1], v[2], facenormal);
1831 VectorNormalize(facenormal);
1832 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
1833 VectorMA(p, offsetdist, facenormal, temp);
1834 for (j = 0, k = 2;j < 3;k = j, j++)
1836 VectorSubtract(v[k], v[j], edgenormal);
1837 CrossProduct(edgenormal, facenormal, sidenormal);
1838 VectorNormalize(sidenormal);
1839 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
1841 VectorMA(temp, offsetdist, sidenormal, temp);
1843 dist = VectorDistance2(temp, p);
1844 if (bestdist > dist)
1847 VectorCopy(temp, out);
1852 static msurface_t *getsurface(prvm_edict_t *ed, int surfacenum)
1856 if (!ed || ed->priv.server->free)
1858 modelindex = ed->fields.server->modelindex;
1859 if (modelindex < 1 || modelindex >= MAX_MODELS)
1861 model = sv.models[modelindex];
1862 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1864 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1868 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
1869 void PF_getsurfacenumpoints(void)
1871 msurface_t *surface;
1872 // return 0 if no such surface
1873 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1875 PRVM_G_FLOAT(OFS_RETURN) = 0;
1879 // note: this (incorrectly) assumes it is a simple polygon
1880 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1882 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
1883 void PF_getsurfacepoint(void)
1886 msurface_t *surface;
1888 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1889 ed = PRVM_G_EDICT(OFS_PARM0);
1890 if (!ed || ed->priv.server->free)
1892 if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
1894 // note: this (incorrectly) assumes it is a simple polygon
1895 pointnum = PRVM_G_FLOAT(OFS_PARM2);
1896 if (pointnum < 0 || pointnum >= surface->num_vertices)
1898 // FIXME: implement rotation/scaling
1899 VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1901 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
1902 void PF_getsurfacenormal(void)
1904 msurface_t *surface;
1906 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1907 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1909 // FIXME: implement rotation/scaling
1910 // note: this (incorrectly) assumes it is a simple polygon
1911 // note: this only returns the first triangle, so it doesn't work very
1912 // well for curved surfaces or arbitrary meshes
1913 TriangleNormal((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 3, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
1914 VectorNormalize(normal);
1915 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1917 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
1918 void PF_getsurfacetexture(void)
1920 msurface_t *surface;
1921 PRVM_G_INT(OFS_RETURN) = 0;
1922 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1924 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
1926 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
1927 void PF_getsurfacenearpoint(void)
1929 int surfacenum, best, modelindex;
1931 vec_t dist, bestdist;
1934 msurface_t *surface;
1936 PRVM_G_FLOAT(OFS_RETURN) = -1;
1937 ed = PRVM_G_EDICT(OFS_PARM0);
1938 point = PRVM_G_VECTOR(OFS_PARM1);
1940 if (!ed || ed->priv.server->free)
1942 modelindex = ed->fields.server->modelindex;
1943 if (modelindex < 1 || modelindex >= MAX_MODELS)
1945 model = sv.models[modelindex];
1946 if (!model->num_surfaces)
1949 // FIXME: implement rotation/scaling
1950 VectorSubtract(point, ed->fields.server->origin, p);
1952 bestdist = 1000000000;
1953 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1955 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1956 // first see if the nearest point on the surface's box is closer than the previous match
1957 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1958 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1959 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1960 dist = VectorLength2(clipped);
1961 if (dist < bestdist)
1963 // it is, check the nearest point on the actual geometry
1964 clippointtosurface(surface, p, clipped);
1965 VectorSubtract(clipped, p, clipped);
1966 dist += VectorLength2(clipped);
1967 if (dist < bestdist)
1969 // that's closer too, store it as the best match
1975 PRVM_G_FLOAT(OFS_RETURN) = best;
1977 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
1978 void PF_getsurfaceclippedpoint(void)
1981 msurface_t *surface;
1983 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1984 ed = PRVM_G_EDICT(OFS_PARM0);
1985 if (!ed || ed->priv.server->free)
1987 if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
1989 // FIXME: implement rotation/scaling
1990 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
1991 clippointtosurface(surface, p, out);
1992 // FIXME: implement rotation/scaling
1993 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1996 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1997 //this function originally written by KrimZon, made shorter by LordHavoc
1998 void PF_clientcommand (void)
2000 client_t *temp_client;
2003 //find client for this entity
2004 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2005 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2007 Con_Print("PF_clientcommand: entity is not a client\n");
2011 temp_client = host_client;
2012 host_client = svs.clients + i;
2013 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2014 host_client = temp_client;
2017 //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)
2018 void PF_setattachment (void)
2020 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2021 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2022 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2027 if (e == prog->edicts)
2028 PF_WARNING("setattachment: can not modify world entity\n");
2029 if (e->priv.server->free)
2030 PF_WARNING("setattachment: can not modify free entity\n");
2032 if (tagentity == NULL)
2033 tagentity = prog->edicts;
2035 v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
2037 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2039 v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
2042 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2044 modelindex = (int)tagentity->fields.server->modelindex;
2045 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
2047 v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->fields.server->skin, tagname);
2049 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);
2052 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));
2056 /////////////////////////////////////////
2057 // DP_MD3_TAGINFO extension coded by VorteX
2059 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2064 i = e->fields.server->modelindex;
2065 if (i < 1 || i >= MAX_MODELS)
2067 model = sv.models[i];
2069 return Mod_Alias_GetTagIndexForName(model, e->fields.server->skin, tagname);
2072 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2074 float scale = PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float;
2078 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);
2080 Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], -ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], scale * 0.333);
2083 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2089 && (modelindex = ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS
2090 && (model = sv.models[(int)ent->fields.server->modelindex])
2091 && model->animscenes)
2093 // if model has wrong frame, engine automatically switches to model first frame
2094 frame = (int)ent->fields.server->frame;
2095 if (frame < 0 || frame >= model->numframes)
2097 return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
2099 Matrix4x4_CreateIdentity(out);
2103 // Warnings/errors code:
2104 // 0 - normal (everything all-right)
2107 // 3 - null or non-precached model
2108 // 4 - no tags with requested index
2109 // 5 - runaway loop at attachment chain
2110 extern cvar_t cl_bob;
2111 extern cvar_t cl_bobcycle;
2112 extern cvar_t cl_bobup;
2113 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2117 int modelindex, attachloop;
2118 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2119 prvm_edict_t *attachent;
2122 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
2124 if (ent == prog->edicts)
2126 if (ent->priv.server->free)
2129 modelindex = (int)ent->fields.server->modelindex;
2130 if (modelindex <= 0 || modelindex > MAX_MODELS)
2133 model = sv.models[modelindex];
2135 // get initial tag matrix
2136 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &tagmatrix);
2140 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2142 while ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
2144 if (attachloop >= 256) // prevent runaway looping
2147 // to this entity our entity is attached
2148 attachent = PRVM_EDICT_NUM(val->edict);
2149 // apply transformation by child entity matrix and then by tag on parent entity
2150 SV_GetEntityMatrix(attachent, &entitymatrix, false);
2151 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2152 SV_GetEntityLocalTagMatrix(ent, PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float - 1, &attachmatrix);
2153 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
2154 // next iteration we process the parent entity
2158 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2159 SV_GetEntityMatrix(ent, &entitymatrix, false);
2160 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2162 // RENDER_VIEWMODEL magic
2163 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
2165 Matrix4x4_Copy(&tagmatrix, out);
2166 ent = PRVM_EDICT_NUM(val->edict);
2168 SV_GetEntityMatrix(ent, &entitymatrix, true);
2169 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2172 // Cl_bob, ported from rendering code
2173 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2176 // LordHavoc: this code is *weird*, but not replacable (I think it
2177 // should be done in QC on the server, but oh well, quake is quake)
2178 // LordHavoc: figured out bobup: the time at which the sin is at 180
2179 // degrees (which allows lengthening or squishing the peak or valley)
2180 cycle = sv.time/cl_bobcycle.value;
2181 cycle -= (int)cycle;
2182 if (cycle < cl_bobup.value)
2183 cycle = sin(M_PI * cycle / cl_bobup.value);
2185 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2186 // bob is proportional to velocity in the xy plane
2187 // (don't count Z, or jumping messes it up)
2188 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;
2189 bob = bob*0.3 + bob*0.7*cycle;
2190 out->m[2][3] += bound(-7, bob, 4);
2197 //float(entity ent, string tagname) gettagindex;
2199 void PF_gettagindex (void)
2201 prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
2202 const char *tag_name = PRVM_G_STRING(OFS_PARM1);
2203 int modelindex, tag_index;
2205 if (ent == prog->edicts)
2206 PF_WARNING("gettagindex: can't affect world entity\n");
2207 if (ent->priv.server->free)
2208 PF_WARNING("gettagindex: can't affect free entity\n");
2210 modelindex = (int)ent->fields.server->modelindex;
2212 if (modelindex <= 0 || modelindex > MAX_MODELS)
2213 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2216 tag_index = SV_GetTagIndex(ent, tag_name);
2218 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2220 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2223 //vector(entity ent, float tagindex) gettaginfo;
2224 void PF_gettaginfo (void)
2226 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2227 int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2228 matrix4x4_t tag_matrix;
2231 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2232 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2237 PF_WARNING("gettagindex: can't affect world entity\n");
2240 PF_WARNING("gettagindex: can't affect free entity\n");
2243 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2246 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2249 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2254 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2255 void PF_dropclient (void)
2258 client_t *oldhostclient;
2259 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2260 if (clientnum < 0 || clientnum >= svs.maxclients)
2261 PF_WARNING("dropclient: not a client\n");
2262 if (!svs.clients[clientnum].active)
2263 PF_WARNING("dropclient: that client slot is not connected\n");
2264 oldhostclient = host_client;
2265 host_client = svs.clients + clientnum;
2266 SV_DropClient(false);
2267 host_client = oldhostclient;
2270 //entity() spawnclient (DP_SV_BOTCLIENT)
2271 void PF_spawnclient (void)
2275 prog->xfunction->builtinsprofile += 2;
2277 for (i = 0;i < svs.maxclients;i++)
2279 if (!svs.clients[i].active)
2281 prog->xfunction->builtinsprofile += 100;
2282 SV_ConnectClient (i, NULL);
2283 ed = PRVM_EDICT_NUM(i + 1);
2287 VM_RETURN_EDICT(ed);
2290 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2291 void PF_clienttype (void)
2294 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2295 if (clientnum < 0 || clientnum >= svs.maxclients)
2296 PRVM_G_FLOAT(OFS_RETURN) = 3;
2297 else if (!svs.clients[clientnum].active)
2298 PRVM_G_FLOAT(OFS_RETURN) = 0;
2299 else if (svs.clients[clientnum].netconnection)
2300 PRVM_G_FLOAT(OFS_RETURN) = 1;
2302 PRVM_G_FLOAT(OFS_RETURN) = 2;
2305 prvm_builtin_t vm_sv_builtins[] = {
2307 PF_makevectors, // #1 void(entity e) makevectors
2308 PF_setorigin, // #2 void(entity e, vector o) setorigin
2309 PF_setmodel, // #3 void(entity e, string m) setmodel
2310 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2311 NULL, // #5 void(entity e, vector min, vector max) setabssize
2312 VM_break, // #6 void() break
2313 VM_random, // #7 float() random
2314 PF_sound, // #8 void(entity e, float chan, string samp) sound
2315 VM_normalize, // #9 vector(vector v) normalize
2316 VM_error, // #10 void(string e) error
2317 VM_objerror, // #11 void(string e) objerror
2318 VM_vlen, // #12 float(vector v) vlen
2319 VM_vectoyaw, // #13 float(vector v) vectoyaw
2320 VM_spawn, // #14 entity() spawn
2321 VM_remove, // #15 void(entity e) remove
2322 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2323 PF_checkclient, // #17 entity() clientlist
2324 VM_find, // #18 entity(entity start, .string fld, string match) find
2325 PF_precache_sound, // #19 void(string s) precache_sound
2326 PF_precache_model, // #20 void(string s) precache_model
2327 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2328 PF_findradius, // #22 entity(vector org, float rad) findradius
2329 VM_bprint, // #23 void(string s) bprint
2330 PF_sprint, // #24 void(entity client, string s) sprint
2331 VM_dprint, // #25 void(string s) dprint
2332 VM_ftos, // #26 void(string s) ftos
2333 VM_vtos, // #27 void(string s) vtos
2334 VM_coredump, // #28 void() coredump
2335 VM_traceon, // #29 void() traceon
2336 VM_traceoff, // #30 void() traceoff
2337 VM_eprint, // #31 void(entity e) eprint
2338 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2340 PF_droptofloor, // #34 float() droptofloor
2341 PF_lightstyle, // #35 void(float style, string value) lightstyle
2342 VM_rint, // #36 float(float v) rint
2343 VM_floor, // #37 float(float v) floor
2344 VM_ceil, // #38 float(float v) ceil
2346 PF_checkbottom, // #40 float(entity e) checkbottom
2347 PF_pointcontents, // #41 float(vector v) pointcontents
2349 VM_fabs, // #43 float(float f) fabs
2350 PF_aim, // #44 vector(entity e, float speed) aim
2351 VM_cvar, // #45 float(string s) cvar
2352 VM_localcmd, // #46 void(string s) localcmd
2353 VM_nextent, // #47 entity(entity e) nextent
2354 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
2355 PF_changeyaw, // #49 void() ChangeYaw
2357 VM_vectoangles, // #51 vector(vector v) vectoangles
2358 PF_WriteByte, // #52 void(float to, float f) WriteByte
2359 PF_WriteChar, // #53 void(float to, float f) WriteChar
2360 PF_WriteShort, // #54 void(float to, float f) WriteShort
2361 PF_WriteLong, // #55 void(float to, float f) WriteLong
2362 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
2363 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
2364 PF_WriteString, // #58 void(float to, string s) WriteString
2365 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
2366 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2367 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2368 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2369 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2370 PF_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2371 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2373 SV_MoveToGoal, // #67 void(float step) movetogoal
2374 PF_precache_file, // #68 string(string s) precache_file
2375 PF_makestatic, // #69 void(entity e) makestatic
2376 VM_changelevel, // #70 void(string s) changelevel
2378 VM_cvar_set, // #72 void(string var, string val) cvar_set
2379 PF_centerprint, // #73 void(entity client, strings) centerprint
2380 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2381 PF_precache_model, // #75 string(string s) precache_model2
2382 PF_precache_sound, // #76 string(string s) precache_sound2
2383 PF_precache_file, // #77 string(string s) precache_file2
2384 PF_setspawnparms, // #78 void(entity e) setspawnparms
2387 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2396 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2397 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2398 PF_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2399 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2400 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2401 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2402 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2403 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2404 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2405 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2416 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2417 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2418 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2419 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2420 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2421 VM_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
2422 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2423 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2424 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2425 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2426 e10, e10, e10, e10, e10, e10, e10, e10, // #120-199
2427 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10, // #200-299
2428 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10, // #300-399
2429 VM_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
2430 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
2431 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
2432 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
2433 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2434 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2435 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2436 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2437 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2438 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2439 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2440 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
2441 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2442 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2443 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2444 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2445 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2446 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2447 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2448 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2449 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2450 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2451 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2452 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2453 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2454 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2455 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2456 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2457 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
2458 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
2459 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
2460 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
2461 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
2462 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
2463 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
2464 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
2465 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
2466 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
2467 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
2468 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
2469 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
2470 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
2471 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
2472 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
2473 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
2474 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
2475 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
2476 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
2477 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
2478 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
2479 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
2480 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2481 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2482 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
2483 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
2484 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
2485 PF_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
2486 PF_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
2489 e10, e10, e10, e10 // #460-499 (LordHavoc)
2492 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2494 void VM_SV_Cmd_Init(void)
2499 void VM_SV_Cmd_Reset(void)