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 "
31 "DP_ENT_CUSTOMCOLORMAP "
32 "DP_ENT_EXTERIORMODELTOCLIENT "
34 "DP_ENT_LOWPRECISION "
37 "DP_GFX_EXTERNALTEXTURES "
39 "DP_GFX_QUAKE3MODELTAGS "
43 "DP_HALFLIFE_MAP_CVAR "
49 "DP_MOVETYPEBOUNCEMISSILE "
56 "DP_QC_FINDCHAINFLAGS "
57 "DP_QC_FINDCHAINFLOAT "
60 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
65 "DP_QC_MULTIPLETEMPSTRINGS "
67 "DP_QC_SINCOSSQRTPOW "
70 "DP_QC_TRACE_MOVETYPE_HITMODEL "
71 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
72 "DP_QC_VECTORVECTORS "
78 "DP_SND_DIRECTIONLESSATTNNONE "
87 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
88 "DP_SV_DRAWONLYTOCLIENT "
91 "DP_SV_NODRAWTOCLIENT "
93 "DP_SV_PLAYERPHYSICS "
94 "DP_SV_PRECACHEANYTIME "
96 "DP_SV_ROTATINGBMODEL "
99 "DP_SV_WRITEUNTERMINATEDSTRING "
103 "DP_TE_EXPLOSIONRGB "
105 "DP_TE_PARTICLECUBE "
106 "DP_TE_PARTICLERAIN "
107 "DP_TE_PARTICLESNOW "
109 "DP_TE_QUADEFFECTS1 "
112 "DP_TE_STANDARDEFFECTBUILTINS "
115 "KRIMZON_SV_PARSECLIENTCOMMAND "
119 "PRYDON_CLIENTCURSOR "
120 "TENEBRAE_GFX_DLIGHTS "
122 "NEXUIZ_PLAYERMODEL "
129 Writes new values for v_forward, v_up, and v_right based on angles
133 void PF_makevectors (void)
135 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
142 Writes new values for v_forward, v_up, and v_right based on the given forward vector
143 vectorvectors(vector, vector)
146 void PF_vectorvectors (void)
148 VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward);
149 VectorVectors(prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
156 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.
158 setorigin (entity, origin)
161 void PF_setorigin (void)
166 e = PRVM_G_EDICT(OFS_PARM0);
167 if (e == prog->edicts)
168 PF_WARNING("setorigin: can not modify world entity\n");
169 if (e->priv.server->free)
170 PF_WARNING("setorigin: can not modify free entity\n");
171 org = PRVM_G_VECTOR(OFS_PARM1);
172 VectorCopy (org, e->fields.server->origin);
173 SV_LinkEdict (e, false);
177 void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
181 for (i=0 ; i<3 ; i++)
183 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
185 // set derived values
186 VectorCopy (min, e->fields.server->mins);
187 VectorCopy (max, e->fields.server->maxs);
188 VectorSubtract (max, min, e->fields.server->size);
190 SV_LinkEdict (e, false);
197 the size box is rotated by the current angle
198 LordHavoc: no it isn't...
200 setsize (entity, minvector, maxvector)
203 void PF_setsize (void)
208 e = PRVM_G_EDICT(OFS_PARM0);
209 if (e == prog->edicts)
210 PF_WARNING("setsize: can not modify world entity\n");
211 if (e->priv.server->free)
212 PF_WARNING("setsize: can not modify free entity\n");
213 min = PRVM_G_VECTOR(OFS_PARM1);
214 max = PRVM_G_VECTOR(OFS_PARM2);
215 SetMinMaxSize (e, min, max, false);
223 setmodel(entity, model)
226 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
227 void PF_setmodel (void)
233 e = PRVM_G_EDICT(OFS_PARM0);
234 if (e == prog->edicts)
235 PF_WARNING("setmodel: can not modify world entity\n");
236 if (e->priv.server->free)
237 PF_WARNING("setmodel: can not modify free entity\n");
238 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
239 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
240 e->fields.server->modelindex = i;
246 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
247 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
249 SetMinMaxSize (e, quakemins, quakemaxs, true);
252 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
259 single print to a specific client
261 sprint(clientent, value)
264 void PF_sprint (void)
268 char string[VM_STRINGTEMP_LENGTH];
270 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
272 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
274 Con_Print("tried to sprint to a non-client\n");
278 client = svs.clients + entnum-1;
279 VM_VarString(1, string, sizeof(string));
280 MSG_WriteChar(&client->message,svc_print);
281 MSG_WriteString(&client->message, string);
289 single print to a specific client
291 centerprint(clientent, value)
294 void PF_centerprint (void)
298 char string[VM_STRINGTEMP_LENGTH];
300 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
302 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
304 Con_Print("tried to sprint to a non-client\n");
308 client = svs.clients + entnum-1;
309 VM_VarString(1, string, sizeof(string));
310 MSG_WriteChar(&client->message,svc_centerprint);
311 MSG_WriteString(&client->message, string);
318 particle(origin, color, count)
321 void PF_particle (void)
327 org = PRVM_G_VECTOR(OFS_PARM0);
328 dir = PRVM_G_VECTOR(OFS_PARM1);
329 color = PRVM_G_FLOAT(OFS_PARM2);
330 count = PRVM_G_FLOAT(OFS_PARM3);
331 SV_StartParticle (org, dir, color, count);
341 void PF_ambientsound (void)
345 float vol, attenuation;
348 pos = PRVM_G_VECTOR (OFS_PARM0);
349 samp = PRVM_G_STRING(OFS_PARM1);
350 vol = PRVM_G_FLOAT(OFS_PARM2);
351 attenuation = PRVM_G_FLOAT(OFS_PARM3);
353 // check to see if samp was properly precached
354 soundnum = SV_SoundIndex(samp, 1);
362 // add an svc_spawnambient command to the level signon packet
365 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
367 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
369 MSG_WriteVector(&sv.signon, pos, sv.protocol);
372 MSG_WriteShort (&sv.signon, soundnum);
374 MSG_WriteByte (&sv.signon, soundnum);
376 MSG_WriteByte (&sv.signon, vol*255);
377 MSG_WriteByte (&sv.signon, attenuation*64);
385 Each entity can have eight independant sound sources, like voice,
388 Channel 0 is an auto-allocate channel, the others override anything
389 already running on that entity/channel pair.
391 An attenuation of 0 will play full volume everywhere in the level.
392 Larger attenuations will drop off.
400 prvm_edict_t *entity;
404 entity = PRVM_G_EDICT(OFS_PARM0);
405 channel = PRVM_G_FLOAT(OFS_PARM1);
406 sample = PRVM_G_STRING(OFS_PARM2);
407 volume = PRVM_G_FLOAT(OFS_PARM3) * 255;
408 attenuation = PRVM_G_FLOAT(OFS_PARM4);
410 if (volume < 0 || volume > 255)
411 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
413 if (attenuation < 0 || attenuation > 4)
414 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
416 if (channel < 0 || channel > 7)
417 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
419 SV_StartSound (entity, channel, sample, volume, attenuation);
426 Used for use tracing and shot targeting
427 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
428 if the tryents flag is set.
430 traceline (vector1, vector2, tryents)
433 void PF_traceline (void)
440 prog->xfunction->builtinsprofile += 30;
442 v1 = PRVM_G_VECTOR(OFS_PARM0);
443 v2 = PRVM_G_VECTOR(OFS_PARM1);
444 move = PRVM_G_FLOAT(OFS_PARM2);
445 ent = PRVM_G_EDICT(OFS_PARM3);
447 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
449 prog->globals.server->trace_allsolid = trace.allsolid;
450 prog->globals.server->trace_startsolid = trace.startsolid;
451 prog->globals.server->trace_fraction = trace.fraction;
452 prog->globals.server->trace_inwater = trace.inwater;
453 prog->globals.server->trace_inopen = trace.inopen;
454 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
455 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
456 prog->globals.server->trace_plane_dist = trace.plane.dist;
458 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
460 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
461 // FIXME: add trace_endcontents
469 Used for use tracing and shot targeting
470 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
471 if the tryents flag is set.
473 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
476 // LordHavoc: added this for my own use, VERY useful, similar to traceline
477 void PF_tracebox (void)
479 float *v1, *v2, *m1, *m2;
484 prog->xfunction->builtinsprofile += 30;
486 v1 = PRVM_G_VECTOR(OFS_PARM0);
487 m1 = PRVM_G_VECTOR(OFS_PARM1);
488 m2 = PRVM_G_VECTOR(OFS_PARM2);
489 v2 = PRVM_G_VECTOR(OFS_PARM3);
490 move = PRVM_G_FLOAT(OFS_PARM4);
491 ent = PRVM_G_EDICT(OFS_PARM5);
493 trace = SV_Move (v1, m1, m2, v2, move, ent);
495 prog->globals.server->trace_allsolid = trace.allsolid;
496 prog->globals.server->trace_startsolid = trace.startsolid;
497 prog->globals.server->trace_fraction = trace.fraction;
498 prog->globals.server->trace_inwater = trace.inwater;
499 prog->globals.server->trace_inopen = trace.inopen;
500 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
501 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
502 prog->globals.server->trace_plane_dist = trace.plane.dist;
504 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
506 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
509 extern trace_t SV_Trace_Toss (prvm_edict_t *ent, prvm_edict_t *ignore);
510 void PF_tracetoss (void)
514 prvm_edict_t *ignore;
516 prog->xfunction->builtinsprofile += 600;
518 ent = PRVM_G_EDICT(OFS_PARM0);
519 if (ent == prog->edicts)
520 PF_WARNING("tracetoss: can not use world entity\n");
521 ignore = PRVM_G_EDICT(OFS_PARM1);
523 trace = SV_Trace_Toss (ent, ignore);
525 prog->globals.server->trace_allsolid = trace.allsolid;
526 prog->globals.server->trace_startsolid = trace.startsolid;
527 prog->globals.server->trace_fraction = trace.fraction;
528 prog->globals.server->trace_inwater = trace.inwater;
529 prog->globals.server->trace_inopen = trace.inopen;
530 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
531 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
532 prog->globals.server->trace_plane_dist = trace.plane.dist;
534 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
536 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
544 Returns true if the given entity can move to the given position from it's
545 current position by walking or rolling.
547 scalar checkpos (entity, vector)
550 void PF_checkpos (void)
554 //============================================================================
557 unsigned char checkpvs[MAX_MAP_LEAFS/8];
559 int PF_newcheckclient (int check)
565 // cycle to the next one
567 check = bound(1, check, svs.maxclients);
568 if (check == svs.maxclients)
576 prog->xfunction->builtinsprofile++;
578 if (i == svs.maxclients+1)
580 // look up the client's edict
581 ent = PRVM_EDICT_NUM(i);
582 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
583 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
585 // found a valid client (possibly the same one again)
589 // get the PVS for the entity
590 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
592 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
593 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
602 Returns a client (or object that has a client enemy) that would be a
605 If there is more than one valid option, they are cycled each frame
607 If (self.origin + self.viewofs) is not in the PVS of the current target,
608 it is not returned at all.
613 int c_invis, c_notvis;
614 void PF_checkclient (void)
616 prvm_edict_t *ent, *self;
619 // find a new check if on a new frame
620 if (sv.time - sv.lastchecktime >= 0.1)
622 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
623 sv.lastchecktime = sv.time;
626 // return check if it might be visible
627 ent = PRVM_EDICT_NUM(sv.lastcheck);
628 if (ent->priv.server->free || ent->fields.server->health <= 0)
630 VM_RETURN_EDICT(prog->edicts);
634 // if current entity can't possibly see the check entity, return 0
635 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
636 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
637 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
640 VM_RETURN_EDICT(prog->edicts);
644 // might be able to see it
646 VM_RETURN_EDICT(ent);
649 //============================================================================
656 Sends text over to the client's execution buffer
658 stuffcmd (clientent, value, ...)
661 void PF_stuffcmd (void)
665 char string[VM_STRINGTEMP_LENGTH];
667 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
668 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
670 Con_Print("Can't stuffcmd to a non-client\n");
674 VM_VarString(1, string, sizeof(string));
677 host_client = svs.clients + entnum-1;
678 Host_ClientCommands ("%s", string);
686 Returns a chain of entities that have origins within a spherical area
688 findradius (origin, radius)
691 void PF_findradius (void)
693 prvm_edict_t *ent, *chain;
694 vec_t radius, radius2;
695 vec3_t org, eorg, mins, maxs;
698 prvm_edict_t *touchedicts[MAX_EDICTS];
700 chain = (prvm_edict_t *)prog->edicts;
702 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
703 radius = PRVM_G_FLOAT(OFS_PARM1);
704 radius2 = radius * radius;
706 mins[0] = org[0] - (radius + 1);
707 mins[1] = org[1] - (radius + 1);
708 mins[2] = org[2] - (radius + 1);
709 maxs[0] = org[0] + (radius + 1);
710 maxs[1] = org[1] + (radius + 1);
711 maxs[2] = org[2] + (radius + 1);
712 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
713 if (numtouchedicts > MAX_EDICTS)
715 // this never happens
716 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
717 numtouchedicts = MAX_EDICTS;
719 for (i = 0;i < numtouchedicts;i++)
721 ent = touchedicts[i];
722 prog->xfunction->builtinsprofile++;
723 // Quake did not return non-solid entities but darkplaces does
724 // (note: this is the reason you can't blow up fallen zombies)
725 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
727 // LordHavoc: compare against bounding box rather than center so it
728 // doesn't miss large objects, and use DotProduct instead of Length
729 // for a major speedup
730 VectorSubtract(org, ent->fields.server->origin, eorg);
731 if (sv_gameplayfix_findradiusdistancetobox.integer)
733 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
734 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
735 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
738 VectorMAMAM(1, eorg, 0.5f, ent->fields.server->mins, 0.5f, ent->fields.server->maxs, eorg);
739 if (DotProduct(eorg, eorg) < radius2)
741 ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
746 VM_RETURN_EDICT(chain);
749 void PF_precache_file (void)
750 { // precache_file is only used to copy files with qcc, it does nothing
751 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
755 void PF_precache_sound (void)
757 SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
758 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
761 void PF_precache_model (void)
763 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
764 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
771 float(float yaw, float dist) walkmove
774 void PF_walkmove (void)
782 // assume failure if it returns early
783 PRVM_G_FLOAT(OFS_RETURN) = 0;
785 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
786 if (ent == prog->edicts)
787 PF_WARNING("walkmove: can not modify world entity\n");
788 if (ent->priv.server->free)
789 PF_WARNING("walkmove: can not modify free entity\n");
790 yaw = PRVM_G_FLOAT(OFS_PARM0);
791 dist = PRVM_G_FLOAT(OFS_PARM1);
793 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
796 yaw = yaw*M_PI*2 / 360;
798 move[0] = cos(yaw)*dist;
799 move[1] = sin(yaw)*dist;
802 // save program state, because SV_movestep may call other progs
803 oldf = prog->xfunction;
804 oldself = prog->globals.server->self;
806 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
809 // restore program state
810 prog->xfunction = oldf;
811 prog->globals.server->self = oldself;
821 void PF_droptofloor (void)
827 // assume failure if it returns early
828 PRVM_G_FLOAT(OFS_RETURN) = 0;
830 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
831 if (ent == prog->edicts)
832 PF_WARNING("droptofloor: can not modify world entity\n");
833 if (ent->priv.server->free)
834 PF_WARNING("droptofloor: can not modify free entity\n");
836 VectorCopy (ent->fields.server->origin, end);
839 trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent);
841 if (trace.fraction != 1)
843 VectorCopy (trace.endpos, ent->fields.server->origin);
844 SV_LinkEdict (ent, false);
845 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
846 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
847 PRVM_G_FLOAT(OFS_RETURN) = 1;
848 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
849 ent->priv.server->suspendedinairflag = true;
857 void(float style, string value) lightstyle
860 void PF_lightstyle (void)
867 style = PRVM_G_FLOAT(OFS_PARM0);
868 val = PRVM_G_STRING(OFS_PARM1);
870 if( (unsigned) style >= MAX_LIGHTSTYLES ) {
871 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
874 // change the string in sv
875 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
877 // send message to all clients on this server
878 if (sv.state != ss_active)
881 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
885 MSG_WriteChar (&client->message, svc_lightstyle);
886 MSG_WriteChar (&client->message,style);
887 MSG_WriteString (&client->message, val);
897 void PF_checkbottom (void)
899 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
907 void PF_pointcontents (void)
909 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
916 Pick a vector for the player to shoot along
917 vector aim(entity, missilespeed)
922 prvm_edict_t *ent, *check, *bestent;
923 vec3_t start, dir, end, bestdir;
926 float dist, bestdist;
929 // assume failure if it returns early
930 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
931 // if sv_aim is so high it can't possibly accept anything, skip out early
932 if (sv_aim.value >= 1)
935 ent = PRVM_G_EDICT(OFS_PARM0);
936 if (ent == prog->edicts)
937 PF_WARNING("aim: can not use world entity\n");
938 if (ent->priv.server->free)
939 PF_WARNING("aim: can not use free entity\n");
940 speed = PRVM_G_FLOAT(OFS_PARM1);
942 VectorCopy (ent->fields.server->origin, start);
945 // try sending a trace straight
946 VectorCopy (prog->globals.server->v_forward, dir);
947 VectorMA (start, 2048, dir, end);
948 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
949 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
950 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
952 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
957 // try all possible entities
958 VectorCopy (dir, bestdir);
959 bestdist = sv_aim.value;
962 check = PRVM_NEXT_EDICT(prog->edicts);
963 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
965 prog->xfunction->builtinsprofile++;
966 if (check->fields.server->takedamage != DAMAGE_AIM)
970 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
971 continue; // don't aim at teammate
972 for (j=0 ; j<3 ; j++)
973 end[j] = check->fields.server->origin[j]
974 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
975 VectorSubtract (end, start, dir);
976 VectorNormalize (dir);
977 dist = DotProduct (dir, prog->globals.server->v_forward);
979 continue; // to far to turn
980 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
982 { // can shoot at this one
990 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
991 dist = DotProduct (dir, prog->globals.server->v_forward);
992 VectorScale (prog->globals.server->v_forward, dist, end);
994 VectorNormalize (end);
995 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
999 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1007 This was a major timewaster in progs, so it was converted to C
1010 void PF_changeyaw (void)
1013 float ideal, current, move, speed;
1015 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1016 if (ent == prog->edicts)
1017 PF_WARNING("changeyaw: can not modify world entity\n");
1018 if (ent->priv.server->free)
1019 PF_WARNING("changeyaw: can not modify free entity\n");
1020 current = ANGLEMOD(ent->fields.server->angles[1]);
1021 ideal = ent->fields.server->ideal_yaw;
1022 speed = ent->fields.server->yaw_speed;
1024 if (current == ideal)
1026 move = ideal - current;
1027 if (ideal > current)
1048 ent->fields.server->angles[1] = ANGLEMOD (current + move);
1056 void PF_changepitch (void)
1059 float ideal, current, move, speed;
1062 ent = PRVM_G_EDICT(OFS_PARM0);
1063 if (ent == prog->edicts)
1064 PF_WARNING("changepitch: can not modify world entity\n");
1065 if (ent->priv.server->free)
1066 PF_WARNING("changepitch: can not modify free entity\n");
1067 current = ANGLEMOD( ent->fields.server->angles[0] );
1068 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1069 ideal = val->_float;
1072 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1075 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1076 speed = val->_float;
1079 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1083 if (current == ideal)
1085 move = ideal - current;
1086 if (ideal > current)
1107 ent->fields.server->angles[0] = ANGLEMOD (current + move);
1111 ===============================================================================
1115 ===============================================================================
1118 #define MSG_BROADCAST 0 // unreliable to all
1119 #define MSG_ONE 1 // reliable to one (msg_entity)
1120 #define MSG_ALL 2 // reliable to all
1121 #define MSG_INIT 3 // write to the init string
1123 sizebuf_t *WriteDest (void)
1129 dest = PRVM_G_FLOAT(OFS_PARM0);
1133 return &sv.datagram;
1136 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1137 entnum = PRVM_NUM_FOR_EDICT(ent);
1138 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1140 Con_Printf ("WriteDest: tried to write to non-client\n");
1141 return &sv.reliable_datagram;
1144 return &svs.clients[entnum-1].message;
1147 Con_Printf ("WriteDest: bad destination\n");
1149 return &sv.reliable_datagram;
1158 void PF_WriteByte (void)
1160 MSG_WriteByte (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1163 void PF_WriteChar (void)
1165 MSG_WriteChar (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1168 void PF_WriteShort (void)
1170 MSG_WriteShort (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1173 void PF_WriteLong (void)
1175 MSG_WriteLong (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1178 void PF_WriteAngle (void)
1180 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1183 void PF_WriteCoord (void)
1185 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1188 void PF_WriteString (void)
1190 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1193 void PF_WriteUnterminatedString (void)
1195 MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1199 void PF_WriteEntity (void)
1201 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1204 //////////////////////////////////////////////////////////
1206 void PF_makestatic (void)
1211 ent = PRVM_G_EDICT(OFS_PARM0);
1212 if (ent == prog->edicts)
1213 PF_WARNING("makestatic: can not modify world entity\n");
1214 if (ent->priv.server->free)
1215 PF_WARNING("makestatic: can not modify free entity\n");
1218 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1223 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1224 MSG_WriteShort (&sv.signon, ent->fields.server->modelindex);
1225 MSG_WriteShort (&sv.signon, ent->fields.server->frame);
1229 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1230 MSG_WriteByte (&sv.signon, ent->fields.server->modelindex);
1231 MSG_WriteByte (&sv.signon, ent->fields.server->frame);
1234 MSG_WriteByte (&sv.signon, ent->fields.server->colormap);
1235 MSG_WriteByte (&sv.signon, ent->fields.server->skin);
1236 for (i=0 ; i<3 ; i++)
1238 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1239 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1242 // throw the entity away now
1246 //=============================================================================
1253 void PF_setspawnparms (void)
1259 ent = PRVM_G_EDICT(OFS_PARM0);
1260 i = PRVM_NUM_FOR_EDICT(ent);
1261 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1263 Con_Print("tried to setspawnparms on a non-client\n");
1267 // copy spawn parms out of the client_t
1268 client = svs.clients + i-1;
1269 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1270 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1277 Returns a color vector indicating the lighting at the requested point.
1279 (Internal Operation note: actually measures the light beneath the point, just like
1280 the model lighting on the client)
1285 void PF_getlight (void)
1287 vec3_t ambientcolor, diffusecolor, diffusenormal;
1289 p = PRVM_G_VECTOR(OFS_PARM0);
1290 VectorClear(ambientcolor);
1291 VectorClear(diffusecolor);
1292 VectorClear(diffusenormal);
1293 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1294 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1295 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1298 void PF_registercvar (void)
1300 const char *name, *value;
1301 name = PRVM_G_STRING(OFS_PARM0);
1302 value = PRVM_G_STRING(OFS_PARM1);
1303 PRVM_G_FLOAT(OFS_RETURN) = 0;
1305 // first check to see if it has already been defined
1306 if (Cvar_FindVar (name))
1309 // check for overlap with a command
1310 if (Cmd_Exists (name))
1312 Con_Printf("PF_registercvar: %s is a command\n", name);
1316 Cvar_Get(name, value, 0);
1318 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1325 copies data from one entity to another
1327 copyentity(src, dst)
1330 void PF_copyentity (void)
1332 prvm_edict_t *in, *out;
1333 in = PRVM_G_EDICT(OFS_PARM0);
1334 if (in == prog->edicts)
1335 PF_WARNING("copyentity: can not read world entity\n");
1336 if (in->priv.server->free)
1337 PF_WARNING("copyentity: can not read free entity\n");
1338 out = PRVM_G_EDICT(OFS_PARM1);
1339 if (out == prog->edicts)
1340 PF_WARNING("copyentity: can not modify world entity\n");
1341 if (out->priv.server->free)
1342 PF_WARNING("copyentity: can not modify free entity\n");
1343 memcpy(out->fields.server, in->fields.server, prog->progs->entityfields * 4);
1351 sets the color of a client and broadcasts the update to all connected clients
1353 setcolor(clientent, value)
1356 void PF_setcolor (void)
1362 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1363 i = PRVM_G_FLOAT(OFS_PARM1);
1365 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1367 Con_Print("tried to setcolor a non-client\n");
1371 client = svs.clients + entnum-1;
1374 if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1376 client->edict->fields.server->team = (i & 15) + 1;
1379 if (client->old_colors != client->colors)
1381 client->old_colors = client->colors;
1382 // send notification to all clients
1383 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1384 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1385 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1393 effect(origin, modelname, startframe, framecount, framerate)
1396 void PF_effect (void)
1400 s = PRVM_G_STRING(OFS_PARM1);
1402 PF_WARNING("effect: no model specified\n");
1404 i = SV_ModelIndex(s, 1);
1406 PF_WARNING("effect: model not precached\n");
1407 SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
1410 void PF_te_blood (void)
1412 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1414 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1415 MSG_WriteByte(&sv.datagram, TE_BLOOD);
1417 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1418 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1419 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1421 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1422 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1423 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1425 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1428 void PF_te_bloodshower (void)
1430 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1432 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1433 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1435 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1436 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1437 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1439 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1440 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1441 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1443 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1445 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1448 void PF_te_explosionrgb (void)
1450 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1451 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1453 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1454 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1455 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1457 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1458 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1459 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1462 void PF_te_particlecube (void)
1464 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1466 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1467 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1469 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1470 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1471 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1473 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1474 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1475 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1477 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1478 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1479 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1481 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1483 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1484 // gravity true/false
1485 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1487 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1490 void PF_te_particlerain (void)
1492 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1494 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1495 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1497 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1498 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1499 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1501 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1502 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1503 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1505 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1506 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1507 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1509 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1511 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1514 void PF_te_particlesnow (void)
1516 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1518 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1519 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1521 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1522 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1523 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1525 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1526 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1527 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1529 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1530 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1531 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1533 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1535 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1538 void PF_te_spark (void)
1540 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1542 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1543 MSG_WriteByte(&sv.datagram, TE_SPARK);
1545 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1546 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1547 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1549 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1550 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1551 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1553 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1556 void PF_te_gunshotquad (void)
1558 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1559 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1561 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1562 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1563 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1566 void PF_te_spikequad (void)
1568 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1569 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1571 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1572 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1573 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1576 void PF_te_superspikequad (void)
1578 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1579 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1581 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1582 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1583 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1586 void PF_te_explosionquad (void)
1588 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1589 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1591 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1592 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1593 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1596 void PF_te_smallflash (void)
1598 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1599 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1601 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1602 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1603 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1606 void PF_te_customflash (void)
1608 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
1610 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1611 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
1613 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1614 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1615 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1617 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
1619 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
1621 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
1622 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
1623 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
1626 void PF_te_gunshot (void)
1628 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1629 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
1631 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1632 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1633 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1636 void PF_te_spike (void)
1638 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1639 MSG_WriteByte(&sv.datagram, TE_SPIKE);
1641 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1642 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1643 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1646 void PF_te_superspike (void)
1648 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1649 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
1651 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1652 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1653 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1656 void PF_te_explosion (void)
1658 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1659 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
1661 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1662 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1663 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1666 void PF_te_tarexplosion (void)
1668 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1669 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
1671 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1672 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1673 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1676 void PF_te_wizspike (void)
1678 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1679 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
1681 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1682 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1683 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1686 void PF_te_knightspike (void)
1688 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1689 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
1691 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1692 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1693 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1696 void PF_te_lavasplash (void)
1698 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1699 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
1701 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1702 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1703 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1706 void PF_te_teleport (void)
1708 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1709 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
1711 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1712 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1713 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1716 void PF_te_explosion2 (void)
1718 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1719 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
1721 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1722 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1723 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1725 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM1));
1726 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
1729 void PF_te_lightning1 (void)
1731 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1732 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
1734 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1736 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1737 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1738 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1740 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1741 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1742 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1745 void PF_te_lightning2 (void)
1747 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1748 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
1750 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1752 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1753 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1754 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1756 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1757 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1758 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1761 void PF_te_lightning3 (void)
1763 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1764 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
1766 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1768 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1769 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1770 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1772 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1773 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1774 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1777 void PF_te_beam (void)
1779 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1780 MSG_WriteByte(&sv.datagram, TE_BEAM);
1782 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1784 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1785 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1786 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1788 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1789 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1790 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1793 void PF_te_plasmaburn (void)
1795 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1796 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
1797 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1798 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1799 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1802 void PF_te_flamejet (void)
1804 MSG_WriteByte(&sv.datagram, svc_temp_entity);
1805 MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
1807 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1808 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1809 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1811 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1812 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1813 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1815 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
1818 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
1821 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
1823 bestdist = 1000000000;
1825 for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
1827 // clip original point to each triangle of the surface and find the
1828 // triangle that is closest
1829 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
1830 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
1831 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
1832 TriangleNormal(v[0], v[1], v[2], facenormal);
1833 VectorNormalize(facenormal);
1834 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
1835 VectorMA(p, offsetdist, facenormal, temp);
1836 for (j = 0, k = 2;j < 3;k = j, j++)
1838 VectorSubtract(v[k], v[j], edgenormal);
1839 CrossProduct(edgenormal, facenormal, sidenormal);
1840 VectorNormalize(sidenormal);
1841 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
1843 VectorMA(temp, offsetdist, sidenormal, temp);
1845 dist = VectorDistance2(temp, p);
1846 if (bestdist > dist)
1849 VectorCopy(temp, out);
1854 static msurface_t *getsurface(prvm_edict_t *ed, int surfacenum)
1858 if (!ed || ed->priv.server->free)
1860 modelindex = ed->fields.server->modelindex;
1861 if (modelindex < 1 || modelindex >= MAX_MODELS)
1863 model = sv.models[modelindex];
1864 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1866 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1870 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
1871 void PF_getsurfacenumpoints(void)
1873 msurface_t *surface;
1874 // return 0 if no such surface
1875 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1877 PRVM_G_FLOAT(OFS_RETURN) = 0;
1881 // note: this (incorrectly) assumes it is a simple polygon
1882 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1884 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
1885 void PF_getsurfacepoint(void)
1888 msurface_t *surface;
1890 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1891 ed = PRVM_G_EDICT(OFS_PARM0);
1892 if (!ed || ed->priv.server->free)
1894 if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
1896 // note: this (incorrectly) assumes it is a simple polygon
1897 pointnum = PRVM_G_FLOAT(OFS_PARM2);
1898 if (pointnum < 0 || pointnum >= surface->num_vertices)
1900 // FIXME: implement rotation/scaling
1901 VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1903 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
1904 void PF_getsurfacenormal(void)
1906 msurface_t *surface;
1908 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1909 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1911 // FIXME: implement rotation/scaling
1912 // note: this (incorrectly) assumes it is a simple polygon
1913 // note: this only returns the first triangle, so it doesn't work very
1914 // well for curved surfaces or arbitrary meshes
1915 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);
1916 VectorNormalize(normal);
1917 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1919 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
1920 void PF_getsurfacetexture(void)
1922 msurface_t *surface;
1923 PRVM_G_INT(OFS_RETURN) = 0;
1924 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
1926 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
1928 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
1929 void PF_getsurfacenearpoint(void)
1931 int surfacenum, best, modelindex;
1933 vec_t dist, bestdist;
1936 msurface_t *surface;
1938 PRVM_G_FLOAT(OFS_RETURN) = -1;
1939 ed = PRVM_G_EDICT(OFS_PARM0);
1940 point = PRVM_G_VECTOR(OFS_PARM1);
1942 if (!ed || ed->priv.server->free)
1944 modelindex = ed->fields.server->modelindex;
1945 if (modelindex < 1 || modelindex >= MAX_MODELS)
1947 model = sv.models[modelindex];
1948 if (!model->num_surfaces)
1951 // FIXME: implement rotation/scaling
1952 VectorSubtract(point, ed->fields.server->origin, p);
1954 bestdist = 1000000000;
1955 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1957 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1958 // first see if the nearest point on the surface's box is closer than the previous match
1959 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1960 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1961 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1962 dist = VectorLength2(clipped);
1963 if (dist < bestdist)
1965 // it is, check the nearest point on the actual geometry
1966 clippointtosurface(surface, p, clipped);
1967 VectorSubtract(clipped, p, clipped);
1968 dist += VectorLength2(clipped);
1969 if (dist < bestdist)
1971 // that's closer too, store it as the best match
1977 PRVM_G_FLOAT(OFS_RETURN) = best;
1979 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
1980 void PF_getsurfaceclippedpoint(void)
1983 msurface_t *surface;
1985 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1986 ed = PRVM_G_EDICT(OFS_PARM0);
1987 if (!ed || ed->priv.server->free)
1989 if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
1991 // FIXME: implement rotation/scaling
1992 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
1993 clippointtosurface(surface, p, out);
1994 // FIXME: implement rotation/scaling
1995 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1998 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1999 //this function originally written by KrimZon, made shorter by LordHavoc
2000 void PF_clientcommand (void)
2002 client_t *temp_client;
2005 //find client for this entity
2006 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2007 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2009 Con_Print("PF_clientcommand: entity is not a client\n");
2013 temp_client = host_client;
2014 host_client = svs.clients + i;
2015 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2016 host_client = temp_client;
2019 //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)
2020 void PF_setattachment (void)
2022 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2023 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2024 const char *tagname = PRVM_G_STRING(OFS_PARM2);
2029 if (e == prog->edicts)
2030 PF_WARNING("setattachment: can not modify world entity\n");
2031 if (e->priv.server->free)
2032 PF_WARNING("setattachment: can not modify free entity\n");
2034 if (tagentity == NULL)
2035 tagentity = prog->edicts;
2037 v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
2039 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2041 v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
2044 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2046 modelindex = (int)tagentity->fields.server->modelindex;
2047 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
2049 v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->fields.server->skin, tagname);
2051 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);
2054 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));
2058 /////////////////////////////////////////
2059 // DP_MD3_TAGINFO extension coded by VorteX
2061 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2066 i = e->fields.server->modelindex;
2067 if (i < 1 || i >= MAX_MODELS)
2069 model = sv.models[i];
2071 return Mod_Alias_GetTagIndexForName(model, e->fields.server->skin, tagname);
2074 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2076 float scale = PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float;
2080 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);
2082 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);
2085 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2091 && (modelindex = ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS
2092 && (model = sv.models[(int)ent->fields.server->modelindex])
2093 && model->animscenes)
2095 // if model has wrong frame, engine automatically switches to model first frame
2096 frame = (int)ent->fields.server->frame;
2097 if (frame < 0 || frame >= model->numframes)
2099 return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
2101 Matrix4x4_CreateIdentity(out);
2105 // Warnings/errors code:
2106 // 0 - normal (everything all-right)
2109 // 3 - null or non-precached model
2110 // 4 - no tags with requested index
2111 // 5 - runaway loop at attachment chain
2112 extern cvar_t cl_bob;
2113 extern cvar_t cl_bobcycle;
2114 extern cvar_t cl_bobup;
2115 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2119 int modelindex, attachloop;
2120 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2123 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
2125 if (ent == prog->edicts)
2127 if (ent->priv.server->free)
2130 modelindex = (int)ent->fields.server->modelindex;
2131 if (modelindex <= 0 || modelindex > MAX_MODELS)
2134 model = sv.models[modelindex];
2136 Matrix4x4_CreateIdentity(&tagmatrix);
2137 // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2141 if (attachloop >= 256) // prevent runaway looping
2143 // apply transformation by child's tagindex on parent entity and then
2144 // by parent entity itself
2145 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2146 if (ret && attachloop == 0)
2148 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2149 SV_GetEntityMatrix(ent, &entitymatrix, false);
2150 Matrix4x4_Concat(&tagmatrix, &entitymatrix, out);
2151 // next iteration we process the parent entity
2152 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
2154 tagindex = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
2155 ent = PRVM_EDICT_NUM(val->edict);
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)