2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
26 mempool_t *pr_strings_mempool;
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
34 static char *PR_GetTempString(void)
37 s = pr_string_temp[pr_string_tempindex];
38 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
42 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
43 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
44 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
48 ===============================================================================
52 ===============================================================================
56 void PF_VarString(int first, char *out, int outlength)
62 outend = out + outlength - 1;
63 for (i = first;i < pr_argc && out < outend;i++)
65 s = G_STRING((OFS_PARM0+i*3));
66 while (out < outend && *s)
72 char *ENGINE_EXTENSIONS =
89 "DP_ENT_CUSTOMCOLORMAP "
90 "DP_ENT_EXTERIORMODELTOCLIENT "
92 "DP_ENT_LOWPRECISION "
95 "DP_GFX_EXTERNALTEXTURES "
97 "DP_GFX_QUAKE3MODELTAGS "
101 "DP_HALFLIFE_MAP_CVAR "
106 "DP_MOVETYPEBOUNCEMISSILE "
113 "DP_QC_FINDCHAINFLAGS "
114 "DP_QC_FINDCHAINFLOAT "
117 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
122 "DP_QC_MULTIPLETEMPSTRINGS "
124 "DP_QC_SINCOSSQRTPOW "
127 "DP_QC_TRACE_MOVETYPE_HITMODEL "
128 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
129 "DP_QC_VECTORVECTORS "
134 "DP_SND_DIRECTIONLESSATTNNONE "
141 "DP_SV_CLIENTCOLORS "
143 "DP_SV_DRAWONLYTOCLIENT "
146 "DP_SV_NODRAWTOCLIENT "
148 "DP_SV_PLAYERPHYSICS "
150 "DP_SV_ROTATINGBMODEL "
156 "DP_TE_EXPLOSIONRGB "
158 "DP_TE_PARTICLECUBE "
159 "DP_TE_PARTICLERAIN "
160 "DP_TE_PARTICLESNOW "
162 "DP_TE_QUADEFFECTS1 "
165 "DP_TE_STANDARDEFFECTBUILTINS "
168 "KRIMZON_SV_PARSECLIENTCOMMAND "
172 "PRYDON_CLIENTCURSOR "
173 "TENEBRAE_GFX_DLIGHTS "
175 "NEXUIZ_PLAYERMODEL "
179 qboolean checkextension(char *name)
184 for (e = ENGINE_EXTENSIONS;*e;e++)
191 while (*e && *e != ' ')
193 if (e - start == len)
194 if (!strncasecmp(start, name, len))
204 returns true if the extension is supported by the server
206 checkextension(extensionname)
209 void PF_checkextension (void)
211 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
218 This is a TERMINAL error, which will kill off the entire server.
227 char string[STRINGTEMP_LENGTH];
229 PF_VarString(0, string, sizeof(string));
230 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
231 ed = PROG_TO_EDICT(pr_global_struct->self);
234 PF_ERROR("Program error");
241 Dumps out self, then an error message. The program is aborted and self is
242 removed, but the level can continue.
247 void PF_objerror (void)
250 char string[STRINGTEMP_LENGTH];
252 PF_VarString(0, string, sizeof(string));
253 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
254 ed = PROG_TO_EDICT(pr_global_struct->self);
264 Writes new values for v_forward, v_up, and v_right based on angles
268 void PF_makevectors (void)
270 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
277 Writes new values for v_forward, v_up, and v_right based on the given forward vector
278 vectorvectors(vector, vector)
281 void PF_vectorvectors (void)
283 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
284 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
291 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.
293 setorigin (entity, origin)
296 void PF_setorigin (void)
301 e = G_EDICT(OFS_PARM0);
303 PF_WARNING("setorigin: can not modify world entity\n");
305 PF_WARNING("setorigin: can not modify free entity\n");
306 org = G_VECTOR(OFS_PARM1);
307 VectorCopy (org, e->v->origin);
308 SV_LinkEdict (e, false);
312 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
316 for (i=0 ; i<3 ; i++)
318 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
320 // set derived values
321 VectorCopy (min, e->v->mins);
322 VectorCopy (max, e->v->maxs);
323 VectorSubtract (max, min, e->v->size);
325 SV_LinkEdict (e, false);
332 the size box is rotated by the current angle
333 LordHavoc: no it isn't...
335 setsize (entity, minvector, maxvector)
338 void PF_setsize (void)
343 e = G_EDICT(OFS_PARM0);
345 PF_WARNING("setsize: can not modify world entity\n");
347 PF_WARNING("setsize: can not modify free entity\n");
348 min = G_VECTOR(OFS_PARM1);
349 max = G_VECTOR(OFS_PARM2);
350 SetMinMaxSize (e, min, max, false);
358 setmodel(entity, model)
361 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
362 void PF_setmodel (void)
368 e = G_EDICT(OFS_PARM0);
370 PF_WARNING("setmodel: can not modify world entity\n");
372 PF_WARNING("setmodel: can not modify free entity\n");
373 i = SV_ModelIndex(G_STRING(OFS_PARM1), 1);
374 e->v->model = PR_SetString(sv.model_precache[i]);
375 e->v->modelindex = i;
381 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
382 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
384 SetMinMaxSize (e, quakemins, quakemaxs, true);
387 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
394 broadcast print to everyone on server
399 void PF_bprint (void)
401 char string[STRINGTEMP_LENGTH];
402 PF_VarString(0, string, sizeof(string));
403 SV_BroadcastPrint(string);
410 single print to a specific client
412 sprint(clientent, value)
415 void PF_sprint (void)
419 char string[STRINGTEMP_LENGTH];
421 entnum = G_EDICTNUM(OFS_PARM0);
423 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
425 Con_Print("tried to sprint to a non-client\n");
429 client = svs.clients + entnum-1;
430 PF_VarString(1, string, sizeof(string));
431 MSG_WriteChar(&client->message,svc_print);
432 MSG_WriteString(&client->message, string);
440 single print to a specific client
442 centerprint(clientent, value)
445 void PF_centerprint (void)
449 char string[STRINGTEMP_LENGTH];
451 entnum = G_EDICTNUM(OFS_PARM0);
453 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
455 Con_Print("tried to sprint to a non-client\n");
459 client = svs.clients + entnum-1;
460 PF_VarString(1, string, sizeof(string));
461 MSG_WriteChar(&client->message,svc_centerprint);
462 MSG_WriteString(&client->message, string);
470 vector normalize(vector)
473 void PF_normalize (void)
479 value1 = G_VECTOR(OFS_PARM0);
481 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
485 newvalue[0] = newvalue[1] = newvalue[2] = 0;
489 newvalue[0] = value1[0] * new;
490 newvalue[1] = value1[1] * new;
491 newvalue[2] = value1[2] * new;
494 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
509 value1 = G_VECTOR(OFS_PARM0);
511 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
514 G_FLOAT(OFS_RETURN) = new;
521 float vectoyaw(vector)
524 void PF_vectoyaw (void)
529 value1 = G_VECTOR(OFS_PARM0);
531 if (value1[1] == 0 && value1[0] == 0)
535 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
540 G_FLOAT(OFS_RETURN) = yaw;
548 vector vectoangles(vector)
551 void PF_vectoangles (void)
553 double value1[3], forward, yaw, pitch;
555 VectorCopy(G_VECTOR(OFS_PARM0), value1);
557 if (value1[1] == 0 && value1[0] == 0)
567 // LordHavoc: optimized a bit
570 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
574 else if (value1[1] > 0)
579 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
580 pitch = (atan2(value1[2], forward) * 180 / M_PI);
585 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
592 Returns a number from 0<= num < 1
597 void PF_random (void)
599 G_FLOAT(OFS_RETURN) = lhrandom(0, 1);
606 particle(origin, color, count)
609 void PF_particle (void)
615 org = G_VECTOR(OFS_PARM0);
616 dir = G_VECTOR(OFS_PARM1);
617 color = G_FLOAT(OFS_PARM2);
618 count = G_FLOAT(OFS_PARM3);
619 SV_StartParticle (org, dir, color, count);
629 void PF_ambientsound (void)
633 float vol, attenuation;
636 pos = G_VECTOR (OFS_PARM0);
637 samp = G_STRING(OFS_PARM1);
638 vol = G_FLOAT(OFS_PARM2);
639 attenuation = G_FLOAT(OFS_PARM3);
641 // check to see if samp was properly precached
642 soundnum = SV_SoundIndex(samp, 1);
650 // add an svc_spawnambient command to the level signon packet
653 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
655 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
657 MSG_WriteVector(&sv.signon, pos, sv.protocol);
660 MSG_WriteShort (&sv.signon, soundnum);
662 MSG_WriteByte (&sv.signon, soundnum);
664 MSG_WriteByte (&sv.signon, vol*255);
665 MSG_WriteByte (&sv.signon, attenuation*64);
673 Each entity can have eight independant sound sources, like voice,
676 Channel 0 is an auto-allocate channel, the others override anything
677 already running on that entity/channel pair.
679 An attenuation of 0 will play full volume everywhere in the level.
680 Larger attenuations will drop off.
692 entity = G_EDICT(OFS_PARM0);
693 channel = G_FLOAT(OFS_PARM1);
694 sample = G_STRING(OFS_PARM2);
695 volume = G_FLOAT(OFS_PARM3) * 255;
696 attenuation = G_FLOAT(OFS_PARM4);
698 if (volume < 0 || volume > 255)
699 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
701 if (attenuation < 0 || attenuation > 4)
702 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
704 if (channel < 0 || channel > 7)
705 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
707 SV_StartSound (entity, channel, sample, volume, attenuation);
719 PF_ERROR("break: break statement\n");
726 Used for use tracing and shot targeting
727 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
728 if the tryents flag is set.
730 traceline (vector1, vector2, tryents)
733 void PF_traceline (void)
740 pr_xfunction->builtinsprofile += 30;
742 v1 = G_VECTOR(OFS_PARM0);
743 v2 = G_VECTOR(OFS_PARM1);
744 move = G_FLOAT(OFS_PARM2);
745 ent = G_EDICT(OFS_PARM3);
747 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
749 pr_global_struct->trace_allsolid = trace.allsolid;
750 pr_global_struct->trace_startsolid = trace.startsolid;
751 pr_global_struct->trace_fraction = trace.fraction;
752 pr_global_struct->trace_inwater = trace.inwater;
753 pr_global_struct->trace_inopen = trace.inopen;
754 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
755 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
756 pr_global_struct->trace_plane_dist = trace.plane.dist;
758 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
760 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
761 // FIXME: add trace_endcontents
769 Used for use tracing and shot targeting
770 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
771 if the tryents flag is set.
773 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
776 // LordHavoc: added this for my own use, VERY useful, similar to traceline
777 void PF_tracebox (void)
779 float *v1, *v2, *m1, *m2;
784 pr_xfunction->builtinsprofile += 30;
786 v1 = G_VECTOR(OFS_PARM0);
787 m1 = G_VECTOR(OFS_PARM1);
788 m2 = G_VECTOR(OFS_PARM2);
789 v2 = G_VECTOR(OFS_PARM3);
790 move = G_FLOAT(OFS_PARM4);
791 ent = G_EDICT(OFS_PARM5);
793 trace = SV_Move (v1, m1, m2, v2, move, ent);
795 pr_global_struct->trace_allsolid = trace.allsolid;
796 pr_global_struct->trace_startsolid = trace.startsolid;
797 pr_global_struct->trace_fraction = trace.fraction;
798 pr_global_struct->trace_inwater = trace.inwater;
799 pr_global_struct->trace_inopen = trace.inopen;
800 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
801 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
802 pr_global_struct->trace_plane_dist = trace.plane.dist;
804 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
806 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
809 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
810 void PF_TraceToss (void)
816 pr_xfunction->builtinsprofile += 600;
818 ent = G_EDICT(OFS_PARM0);
819 if (ent == sv.edicts)
820 PF_WARNING("tracetoss: can not use world entity\n");
821 ignore = G_EDICT(OFS_PARM1);
823 trace = SV_Trace_Toss (ent, ignore);
825 pr_global_struct->trace_allsolid = trace.allsolid;
826 pr_global_struct->trace_startsolid = trace.startsolid;
827 pr_global_struct->trace_fraction = trace.fraction;
828 pr_global_struct->trace_inwater = trace.inwater;
829 pr_global_struct->trace_inopen = trace.inopen;
830 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
831 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
832 pr_global_struct->trace_plane_dist = trace.plane.dist;
834 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
836 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
844 Returns true if the given entity can move to the given position from it's
845 current position by walking or rolling.
847 scalar checkpos (entity, vector)
850 void PF_checkpos (void)
854 //============================================================================
857 qbyte checkpvs[MAX_MAP_LEAFS/8];
859 int PF_newcheckclient (int check)
865 // cycle to the next one
867 check = bound(1, check, svs.maxclients);
868 if (check == svs.maxclients)
876 pr_xfunction->builtinsprofile++;
878 if (i == svs.maxclients+1)
880 // look up the client's edict
882 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
883 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
885 // found a valid client (possibly the same one again)
889 // get the PVS for the entity
890 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
892 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
893 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
902 Returns a client (or object that has a client enemy) that would be a
905 If there is more than one valid option, they are cycled each frame
907 If (self.origin + self.viewofs) is not in the PVS of the current target,
908 it is not returned at all.
913 int c_invis, c_notvis;
914 void PF_checkclient (void)
919 // find a new check if on a new frame
920 if (sv.time - sv.lastchecktime >= 0.1)
922 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
923 sv.lastchecktime = sv.time;
926 // return check if it might be visible
927 ent = EDICT_NUM(sv.lastcheck);
928 if (ent->e->free || ent->v->health <= 0)
930 RETURN_EDICT(sv.edicts);
934 // if current entity can't possibly see the check entity, return 0
935 self = PROG_TO_EDICT(pr_global_struct->self);
936 VectorAdd(self->v->origin, self->v->view_ofs, view);
937 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
940 RETURN_EDICT(sv.edicts);
944 // might be able to see it
949 //============================================================================
956 Sends text over to the client's execution buffer
958 stuffcmd (clientent, value)
961 void PF_stuffcmd (void)
967 entnum = G_EDICTNUM(OFS_PARM0);
968 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
970 Con_Print("Can't stuffcmd to a non-client\n");
973 str = G_STRING(OFS_PARM1);
976 host_client = svs.clients + entnum-1;
977 Host_ClientCommands ("%s", str);
985 Sends text to server console
990 void PF_localcmd (void)
992 Cbuf_AddText(G_STRING(OFS_PARM0));
1004 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1014 void PF_cvar_set (void)
1016 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1023 Returns a chain of entities that have origins within a spherical area
1025 findradius (origin, radius)
1028 void PF_findradius (void)
1030 edict_t *ent, *chain;
1031 vec_t radius, radius2;
1032 vec3_t org, eorg, mins, maxs;
1035 edict_t *touchedicts[MAX_EDICTS];
1037 chain = (edict_t *)sv.edicts;
1039 VectorCopy(G_VECTOR(OFS_PARM0), org);
1040 radius = G_FLOAT(OFS_PARM1);
1041 radius2 = radius * radius;
1043 mins[0] = org[0] - radius;
1044 mins[1] = org[1] - radius;
1045 mins[2] = org[2] - radius;
1046 maxs[0] = org[0] + radius;
1047 maxs[1] = org[1] + radius;
1048 maxs[2] = org[2] + radius;
1049 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1050 if (numtouchedicts > MAX_EDICTS)
1052 // this never happens
1053 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1054 numtouchedicts = MAX_EDICTS;
1056 for (i = 0;i < numtouchedicts;i++)
1058 ent = touchedicts[i];
1059 pr_xfunction->builtinsprofile++;
1060 // LordHavoc: compare against bounding box rather than center so it
1061 // doesn't miss large objects, and use DotProduct instead of Length
1062 // for a major speedup
1063 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1064 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1065 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1066 if (DotProduct(eorg, eorg) < radius2)
1068 ent->v->chain = EDICT_TO_PROG(chain);
1073 RETURN_EDICT(chain);
1082 void PF_dprint (void)
1084 char string[STRINGTEMP_LENGTH];
1085 if (developer.integer)
1087 PF_VarString(0, string, sizeof(string));
1096 v = G_FLOAT(OFS_PARM0);
1098 s = PR_GetTempString();
1099 if ((float)((int)v) == v)
1100 sprintf(s, "%i", (int)v);
1102 sprintf(s, "%f", v);
1103 G_INT(OFS_RETURN) = PR_SetString(s);
1109 v = G_FLOAT(OFS_PARM0);
1110 G_FLOAT(OFS_RETURN) = fabs(v);
1116 s = PR_GetTempString();
1117 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1118 G_INT(OFS_RETURN) = PR_SetString(s);
1124 s = PR_GetTempString();
1125 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1126 G_INT(OFS_RETURN) = PR_SetString(s);
1129 void PF_Spawn (void)
1132 pr_xfunction->builtinsprofile += 20;
1137 void PF_Remove (void)
1140 pr_xfunction->builtinsprofile += 20;
1142 ed = G_EDICT(OFS_PARM0);
1143 if (ed == sv.edicts)
1144 PF_WARNING("remove: tried to remove world\n");
1145 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1146 PF_WARNING("remove: tried to remove a client\n");
1147 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1148 if (ed->e->free && developer.integer)
1149 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1154 // entity (entity start, .string field, string match) find = #5;
1162 e = G_EDICTNUM(OFS_PARM0);
1163 f = G_INT(OFS_PARM1);
1164 s = G_STRING(OFS_PARM2);
1167 RETURN_EDICT(sv.edicts);
1171 for (e++ ; e < sv.num_edicts ; e++)
1173 pr_xfunction->builtinsprofile++;
1187 RETURN_EDICT(sv.edicts);
1190 // LordHavoc: added this for searching float, int, and entity reference fields
1191 void PF_FindFloat (void)
1198 e = G_EDICTNUM(OFS_PARM0);
1199 f = G_INT(OFS_PARM1);
1200 s = G_FLOAT(OFS_PARM2);
1202 for (e++ ; e < sv.num_edicts ; e++)
1204 pr_xfunction->builtinsprofile++;
1208 if (E_FLOAT(ed,f) == s)
1215 RETURN_EDICT(sv.edicts);
1218 // chained search for strings in entity fields
1219 // entity(.string field, string match) findchain = #402;
1220 void PF_findchain (void)
1225 edict_t *ent, *chain;
1227 chain = (edict_t *)sv.edicts;
1229 f = G_INT(OFS_PARM0);
1230 s = G_STRING(OFS_PARM1);
1233 RETURN_EDICT(sv.edicts);
1237 ent = NEXT_EDICT(sv.edicts);
1238 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1240 pr_xfunction->builtinsprofile++;
1243 t = E_STRING(ent,f);
1249 ent->v->chain = EDICT_TO_PROG(chain);
1253 RETURN_EDICT(chain);
1256 // LordHavoc: chained search for float, int, and entity reference fields
1257 // entity(.string field, float match) findchainfloat = #403;
1258 void PF_findchainfloat (void)
1263 edict_t *ent, *chain;
1265 chain = (edict_t *)sv.edicts;
1267 f = G_INT(OFS_PARM0);
1268 s = G_FLOAT(OFS_PARM1);
1270 ent = NEXT_EDICT(sv.edicts);
1271 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1273 pr_xfunction->builtinsprofile++;
1276 if (E_FLOAT(ent,f) != s)
1279 ent->v->chain = EDICT_TO_PROG(chain);
1283 RETURN_EDICT(chain);
1286 // LordHavoc: search for flags in float fields
1287 void PF_findflags (void)
1294 e = G_EDICTNUM(OFS_PARM0);
1295 f = G_INT(OFS_PARM1);
1296 s = (int)G_FLOAT(OFS_PARM2);
1298 for (e++ ; e < sv.num_edicts ; e++)
1300 pr_xfunction->builtinsprofile++;
1304 if ((int)E_FLOAT(ed,f) & s)
1311 RETURN_EDICT(sv.edicts);
1314 // LordHavoc: chained search for flags in float fields
1315 void PF_findchainflags (void)
1320 edict_t *ent, *chain;
1322 chain = (edict_t *)sv.edicts;
1324 f = G_INT(OFS_PARM0);
1325 s = (int)G_FLOAT(OFS_PARM1);
1327 ent = NEXT_EDICT(sv.edicts);
1328 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1330 pr_xfunction->builtinsprofile++;
1333 if (!((int)E_FLOAT(ent,f) & s))
1336 ent->v->chain = EDICT_TO_PROG(chain);
1340 RETURN_EDICT(chain);
1343 void PR_CheckEmptyString (char *s)
1346 PF_ERROR("Bad string");
1349 void PF_precache_file (void)
1350 { // precache_file is only used to copy files with qcc, it does nothing
1351 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1355 void PF_precache_sound (void)
1357 SV_SoundIndex(G_STRING(OFS_PARM0), 2);
1358 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1361 void PF_precache_model (void)
1363 SV_ModelIndex(G_STRING(OFS_PARM0), 2);
1364 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1368 void PF_coredump (void)
1373 void PF_traceon (void)
1378 void PF_traceoff (void)
1383 void PF_eprint (void)
1385 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1392 float(float yaw, float dist) walkmove
1395 void PF_walkmove (void)
1403 // assume failure if it returns early
1404 G_FLOAT(OFS_RETURN) = 0;
1406 ent = PROG_TO_EDICT(pr_global_struct->self);
1407 if (ent == sv.edicts)
1408 PF_WARNING("walkmove: can not modify world entity\n");
1410 PF_WARNING("walkmove: can not modify free entity\n");
1411 yaw = G_FLOAT(OFS_PARM0);
1412 dist = G_FLOAT(OFS_PARM1);
1414 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1417 yaw = yaw*M_PI*2 / 360;
1419 move[0] = cos(yaw)*dist;
1420 move[1] = sin(yaw)*dist;
1423 // save program state, because SV_movestep may call other progs
1424 oldf = pr_xfunction;
1425 oldself = pr_global_struct->self;
1427 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1430 // restore program state
1431 pr_xfunction = oldf;
1432 pr_global_struct->self = oldself;
1442 void PF_droptofloor (void)
1448 // assume failure if it returns early
1449 G_FLOAT(OFS_RETURN) = 0;
1451 ent = PROG_TO_EDICT(pr_global_struct->self);
1452 if (ent == sv.edicts)
1453 PF_WARNING("droptofloor: can not modify world entity\n");
1455 PF_WARNING("droptofloor: can not modify free entity\n");
1457 VectorCopy (ent->v->origin, end);
1460 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1462 if (trace.fraction != 1)
1464 VectorCopy (trace.endpos, ent->v->origin);
1465 SV_LinkEdict (ent, false);
1466 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1467 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1468 G_FLOAT(OFS_RETURN) = 1;
1469 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1470 ent->e->suspendedinairflag = true;
1478 void(float style, string value) lightstyle
1481 void PF_lightstyle (void)
1488 style = G_FLOAT(OFS_PARM0);
1489 val = G_STRING(OFS_PARM1);
1491 // change the string in sv
1492 sv.lightstyles[style] = val;
1494 // send message to all clients on this server
1495 if (sv.state != ss_active)
1498 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1502 MSG_WriteChar (&client->message, svc_lightstyle);
1503 MSG_WriteChar (&client->message,style);
1504 MSG_WriteString (&client->message, val);
1512 f = G_FLOAT(OFS_PARM0);
1514 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1516 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1518 void PF_floor (void)
1520 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1524 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1533 void PF_checkbottom (void)
1535 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1543 void PF_pointcontents (void)
1545 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1552 entity nextent(entity)
1555 void PF_nextent (void)
1560 i = G_EDICTNUM(OFS_PARM0);
1563 pr_xfunction->builtinsprofile++;
1565 if (i == sv.num_edicts)
1567 RETURN_EDICT(sv.edicts);
1583 Pick a vector for the player to shoot along
1584 vector aim(entity, missilespeed)
1589 edict_t *ent, *check, *bestent;
1590 vec3_t start, dir, end, bestdir;
1593 float dist, bestdist;
1596 // assume failure if it returns early
1597 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1598 // if sv_aim is so high it can't possibly accept anything, skip out early
1599 if (sv_aim.value >= 1)
1602 ent = G_EDICT(OFS_PARM0);
1603 if (ent == sv.edicts)
1604 PF_WARNING("aim: can not use world entity\n");
1606 PF_WARNING("aim: can not use free entity\n");
1607 speed = G_FLOAT(OFS_PARM1);
1609 VectorCopy (ent->v->origin, start);
1612 // try sending a trace straight
1613 VectorCopy (pr_global_struct->v_forward, dir);
1614 VectorMA (start, 2048, dir, end);
1615 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1616 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1617 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1619 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1624 // try all possible entities
1625 VectorCopy (dir, bestdir);
1626 bestdist = sv_aim.value;
1629 check = NEXT_EDICT(sv.edicts);
1630 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1632 pr_xfunction->builtinsprofile++;
1633 if (check->v->takedamage != DAMAGE_AIM)
1637 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1638 continue; // don't aim at teammate
1639 for (j=0 ; j<3 ; j++)
1640 end[j] = check->v->origin[j]
1641 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1642 VectorSubtract (end, start, dir);
1643 VectorNormalize (dir);
1644 dist = DotProduct (dir, pr_global_struct->v_forward);
1645 if (dist < bestdist)
1646 continue; // to far to turn
1647 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1648 if (tr.ent == check)
1649 { // can shoot at this one
1657 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1658 dist = DotProduct (dir, pr_global_struct->v_forward);
1659 VectorScale (pr_global_struct->v_forward, dist, end);
1661 VectorNormalize (end);
1662 VectorCopy (end, G_VECTOR(OFS_RETURN));
1666 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1674 This was a major timewaster in progs, so it was converted to C
1677 void PF_changeyaw (void)
1680 float ideal, current, move, speed;
1682 ent = PROG_TO_EDICT(pr_global_struct->self);
1683 if (ent == sv.edicts)
1684 PF_WARNING("changeyaw: can not modify world entity\n");
1686 PF_WARNING("changeyaw: can not modify free entity\n");
1687 current = ANGLEMOD(ent->v->angles[1]);
1688 ideal = ent->v->ideal_yaw;
1689 speed = ent->v->yaw_speed;
1691 if (current == ideal)
1693 move = ideal - current;
1694 if (ideal > current)
1715 ent->v->angles[1] = ANGLEMOD (current + move);
1723 void PF_changepitch (void)
1726 float ideal, current, move, speed;
1729 ent = G_EDICT(OFS_PARM0);
1730 if (ent == sv.edicts)
1731 PF_WARNING("changepitch: can not modify world entity\n");
1733 PF_WARNING("changepitch: can not modify free entity\n");
1734 current = ANGLEMOD( ent->v->angles[0] );
1735 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1736 ideal = val->_float;
1739 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1742 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1743 speed = val->_float;
1746 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1750 if (current == ideal)
1752 move = ideal - current;
1753 if (ideal > current)
1774 ent->v->angles[0] = ANGLEMOD (current + move);
1778 ===============================================================================
1782 ===============================================================================
1785 #define MSG_BROADCAST 0 // unreliable to all
1786 #define MSG_ONE 1 // reliable to one (msg_entity)
1787 #define MSG_ALL 2 // reliable to all
1788 #define MSG_INIT 3 // write to the init string
1790 sizebuf_t *WriteDest (void)
1796 dest = G_FLOAT(OFS_PARM0);
1800 return &sv.datagram;
1803 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1804 entnum = NUM_FOR_EDICT(ent);
1805 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1806 Host_Error("WriteDest: tried to write to non-client\n");
1807 return &svs.clients[entnum-1].message;
1810 return &sv.reliable_datagram;
1816 Host_Error("WriteDest: bad destination");
1823 void PF_WriteByte (void)
1825 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1828 void PF_WriteChar (void)
1830 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1833 void PF_WriteShort (void)
1835 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1838 void PF_WriteLong (void)
1840 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1843 void PF_WriteAngle (void)
1845 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1848 void PF_WriteCoord (void)
1850 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1853 void PF_WriteString (void)
1855 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1859 void PF_WriteEntity (void)
1861 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1864 //=============================================================================
1866 void PF_makestatic (void)
1871 ent = G_EDICT(OFS_PARM0);
1872 if (ent == sv.edicts)
1873 PF_WARNING("makestatic: can not modify world entity\n");
1875 PF_WARNING("makestatic: can not modify free entity\n");
1878 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1883 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1884 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1885 MSG_WriteShort (&sv.signon, ent->v->frame);
1889 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1890 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1891 MSG_WriteByte (&sv.signon, ent->v->frame);
1894 MSG_WriteByte (&sv.signon, ent->v->colormap);
1895 MSG_WriteByte (&sv.signon, ent->v->skin);
1896 for (i=0 ; i<3 ; i++)
1898 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1899 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1902 // throw the entity away now
1906 //=============================================================================
1913 void PF_setspawnparms (void)
1919 ent = G_EDICT(OFS_PARM0);
1920 i = NUM_FOR_EDICT(ent);
1921 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1923 Con_Print("tried to setspawnparms on a non-client\n");
1927 // copy spawn parms out of the client_t
1928 client = svs.clients + i-1;
1929 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1930 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1938 void PF_changelevel (void)
1942 // make sure we don't issue two changelevels
1943 if (svs.changelevel_issued)
1945 svs.changelevel_issued = true;
1947 s = G_STRING(OFS_PARM0);
1948 Cbuf_AddText (va("changelevel %s\n",s));
1953 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1958 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1963 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1970 Returns a vector of length < 1
1975 void PF_randomvec (void)
1980 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1981 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1982 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1984 while (DotProduct(temp, temp) >= 1);
1985 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1992 Returns a color vector indicating the lighting at the requested point.
1994 (Internal Operation note: actually measures the light beneath the point, just like
1995 the model lighting on the client)
2000 void PF_GetLight (void)
2002 vec3_t ambientcolor, diffusecolor, diffusenormal;
2004 p = G_VECTOR(OFS_PARM0);
2005 VectorClear(ambientcolor);
2006 VectorClear(diffusecolor);
2007 VectorClear(diffusenormal);
2008 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2009 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2010 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2013 void PF_registercvar (void)
2016 name = G_STRING(OFS_PARM0);
2017 value = G_STRING(OFS_PARM1);
2018 G_FLOAT(OFS_RETURN) = 0;
2020 // first check to see if it has already been defined
2021 if (Cvar_FindVar (name))
2024 // check for overlap with a command
2025 if (Cmd_Exists (name))
2027 Con_Printf("PF_registercvar: %s is a command\n", name);
2031 Cvar_Get(name, value, 0);
2033 G_FLOAT(OFS_RETURN) = 1; // success
2040 returns the minimum of two supplied floats
2047 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2049 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2050 else if (pr_argc >= 3)
2053 float f = G_FLOAT(OFS_PARM0);
2054 for (i = 1;i < pr_argc;i++)
2055 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2056 f = G_FLOAT((OFS_PARM0+i*3));
2057 G_FLOAT(OFS_RETURN) = f;
2061 G_FLOAT(OFS_RETURN) = 0;
2062 PF_WARNING("min: must supply at least 2 floats\n");
2070 returns the maximum of two supplied floats
2077 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2079 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2080 else if (pr_argc >= 3)
2083 float f = G_FLOAT(OFS_PARM0);
2084 for (i = 1;i < pr_argc;i++)
2085 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2086 f = G_FLOAT((OFS_PARM0+i*3));
2087 G_FLOAT(OFS_RETURN) = f;
2091 G_FLOAT(OFS_RETURN) = 0;
2092 PF_WARNING("max: must supply at least 2 floats\n");
2100 returns number bounded by supplied range
2102 min(min, value, max)
2105 void PF_bound (void)
2107 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2114 returns a raised to power b
2121 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2128 copies data from one entity to another
2130 copyentity(src, dst)
2133 void PF_copyentity (void)
2136 in = G_EDICT(OFS_PARM0);
2137 if (in == sv.edicts)
2138 PF_WARNING("copyentity: can not read world entity\n");
2140 PF_WARNING("copyentity: can not read free entity\n");
2141 out = G_EDICT(OFS_PARM1);
2142 if (out == sv.edicts)
2143 PF_WARNING("copyentity: can not modify world entity\n");
2145 PF_WARNING("copyentity: can not modify free entity\n");
2146 memcpy(out->v, in->v, progs->entityfields * 4);
2153 sets the color of a client and broadcasts the update to all connected clients
2155 setcolor(clientent, value)
2158 void PF_setcolor (void)
2164 entnum = G_EDICTNUM(OFS_PARM0);
2165 i = G_FLOAT(OFS_PARM1);
2167 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2169 Con_Print("tried to setcolor a non-client\n");
2173 client = svs.clients + entnum-1;
2176 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2178 client->edict->v->team = (i & 15) + 1;
2181 if (client->old_colors != client->colors)
2183 client->old_colors = client->colors;
2184 // send notification to all clients
2185 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2186 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2187 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2195 effect(origin, modelname, startframe, framecount, framerate)
2198 void PF_effect (void)
2202 s = G_STRING(OFS_PARM1);
2204 PF_WARNING("effect: no model specified\n");
2206 i = SV_ModelIndex(s, 1);
2208 PF_WARNING("effect: model not precached\n");
2209 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2212 void PF_te_blood (void)
2214 if (G_FLOAT(OFS_PARM2) < 1)
2216 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2217 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2219 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2221 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2223 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2224 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2225 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2227 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2230 void PF_te_bloodshower (void)
2232 if (G_FLOAT(OFS_PARM3) < 1)
2234 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2235 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2237 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2238 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2239 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2245 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2247 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2250 void PF_te_explosionrgb (void)
2252 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2253 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2255 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2256 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2257 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2259 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2260 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2261 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2264 void PF_te_particlecube (void)
2266 if (G_FLOAT(OFS_PARM3) < 1)
2268 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2269 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2271 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2272 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2273 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2275 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2276 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2277 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2279 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2280 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2281 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2283 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2285 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2286 // gravity true/false
2287 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2289 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2292 void PF_te_particlerain (void)
2294 if (G_FLOAT(OFS_PARM3) < 1)
2296 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2297 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2299 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2300 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2301 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2305 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2309 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2311 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2313 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2316 void PF_te_particlesnow (void)
2318 if (G_FLOAT(OFS_PARM3) < 1)
2320 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2321 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2324 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2325 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2335 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2337 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2340 void PF_te_spark (void)
2342 if (G_FLOAT(OFS_PARM2) < 1)
2344 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2345 MSG_WriteByte(&sv.datagram, TE_SPARK);
2347 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2348 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2349 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2351 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2352 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2353 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2355 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2358 void PF_te_gunshotquad (void)
2360 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2361 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2363 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2364 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2365 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2368 void PF_te_spikequad (void)
2370 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2371 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2373 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2374 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2375 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2378 void PF_te_superspikequad (void)
2380 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2381 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2383 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2384 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2385 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2388 void PF_te_explosionquad (void)
2390 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2391 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2393 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2394 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2395 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2398 void PF_te_smallflash (void)
2400 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2401 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2403 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2404 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2405 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2408 void PF_te_customflash (void)
2410 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2412 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2413 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2415 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2416 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2417 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2419 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2421 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2423 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2424 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2425 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2428 void PF_te_gunshot (void)
2430 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2431 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2433 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2434 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2435 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2438 void PF_te_spike (void)
2440 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2441 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2443 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2444 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2445 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2448 void PF_te_superspike (void)
2450 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2451 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2453 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2454 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2455 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2458 void PF_te_explosion (void)
2460 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2461 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2463 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2464 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2465 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2468 void PF_te_tarexplosion (void)
2470 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2471 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2473 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2474 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2475 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2478 void PF_te_wizspike (void)
2480 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2481 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2483 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2484 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2485 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2488 void PF_te_knightspike (void)
2490 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2491 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2493 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2494 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2495 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2498 void PF_te_lavasplash (void)
2500 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2501 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2503 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2504 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2505 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2508 void PF_te_teleport (void)
2510 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2511 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2513 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2514 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2515 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2518 void PF_te_explosion2 (void)
2520 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2521 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2523 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2524 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2525 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2527 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2528 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2531 void PF_te_lightning1 (void)
2533 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2534 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2536 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2538 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2539 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2540 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2542 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2543 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2544 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2547 void PF_te_lightning2 (void)
2549 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2550 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2552 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2554 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2555 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2556 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2558 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2559 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2560 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2563 void PF_te_lightning3 (void)
2565 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2566 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2568 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2570 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2571 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2572 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2574 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2575 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2576 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2579 void PF_te_beam (void)
2581 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2582 MSG_WriteByte(&sv.datagram, TE_BEAM);
2584 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2586 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2587 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2588 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2591 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2592 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2595 void PF_te_plasmaburn (void)
2597 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2598 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2599 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2600 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2601 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2604 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
2607 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2608 bestdist = 1000000000;
2610 for (i = 0;i < surface->num_triangles;i++)
2612 // clip original point to each triangle of the surface and find the
2613 // triangle that is closest
2614 v[0] = (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 0] * 3;
2615 v[1] = (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 1] * 3;
2616 v[2] = (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 2] * 3;
2617 TriangleNormal(v[0], v[1], v[2], facenormal);
2618 VectorNormalize(facenormal);
2619 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2620 VectorMA(p, offsetdist, facenormal, temp);
2621 for (j = 0, k = 2;j < 3;k = j, j++)
2623 VectorSubtract(v[k], v[j], edgenormal);
2624 CrossProduct(edgenormal, facenormal, sidenormal);
2625 VectorNormalize(sidenormal);
2626 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2628 VectorMA(temp, offsetdist, sidenormal, temp);
2630 dist = VectorDistance2(temp, p);
2631 if (bestdist > dist)
2634 VectorCopy(temp, out);
2639 static msurface_t *getsurface(edict_t *ed, int surfacenum)
2643 if (!ed || ed->e->free)
2645 modelindex = ed->v->modelindex;
2646 if (modelindex < 1 || modelindex >= MAX_MODELS)
2648 model = sv.models[modelindex];
2649 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2651 return model->brush.data_surfaces + surfacenum + model->firstmodelsurface;
2655 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2656 void PF_getsurfacenumpoints(void)
2658 msurface_t *surface;
2659 // return 0 if no such surface
2660 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2662 G_FLOAT(OFS_RETURN) = 0;
2666 // note: this (incorrectly) assumes it is a simple polygon
2667 G_FLOAT(OFS_RETURN) = surface->num_vertices;
2669 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2670 void PF_getsurfacepoint(void)
2673 msurface_t *surface;
2675 VectorClear(G_VECTOR(OFS_RETURN));
2676 ed = G_EDICT(OFS_PARM0);
2677 if (!ed || ed->e->free)
2679 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2681 // note: this (incorrectly) assumes it is a simple polygon
2682 pointnum = G_FLOAT(OFS_PARM2);
2683 if (pointnum < 0 || pointnum >= surface->num_vertices)
2685 // FIXME: implement rotation/scaling
2686 VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2688 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2689 void PF_getsurfacenormal(void)
2691 msurface_t *surface;
2693 VectorClear(G_VECTOR(OFS_RETURN));
2694 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2696 // FIXME: implement rotation/scaling
2697 // note: this (incorrectly) assumes it is a simple polygon
2698 // note: this only returns the first triangle, so it doesn't work very
2699 // well for curved surfaces or arbitrary meshes
2700 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);
2701 VectorNormalize(normal);
2702 VectorCopy(normal, G_VECTOR(OFS_RETURN));
2704 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2705 void PF_getsurfacetexture(void)
2707 msurface_t *surface;
2708 G_INT(OFS_RETURN) = 0;
2709 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2711 G_INT(OFS_RETURN) = PR_SetString(surface->texture->name);
2713 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2714 void PF_getsurfacenearpoint(void)
2716 int surfacenum, best, modelindex;
2718 vec_t dist, bestdist;
2721 msurface_t *surface;
2723 G_FLOAT(OFS_RETURN) = -1;
2724 ed = G_EDICT(OFS_PARM0);
2725 point = G_VECTOR(OFS_PARM1);
2727 if (!ed || ed->e->free)
2729 modelindex = ed->v->modelindex;
2730 if (modelindex < 1 || modelindex >= MAX_MODELS)
2732 model = sv.models[modelindex];
2733 if (!model->brush.num_surfaces)
2736 // FIXME: implement rotation/scaling
2737 VectorSubtract(point, ed->v->origin, p);
2739 bestdist = 1000000000;
2740 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2742 surface = model->brush.data_surfaces + surfacenum + model->firstmodelsurface;
2743 // first see if the nearest point on the surface's box is closer than the previous match
2744 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2745 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2746 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2747 dist = VectorLength2(clipped);
2748 if (dist < bestdist)
2750 // it is, check the nearest point on the actual geometry
2751 clippointtosurface(surface, p, clipped);
2752 VectorSubtract(clipped, p, clipped);
2753 dist += VectorLength2(clipped);
2754 if (dist < bestdist)
2756 // that's closer too, store it as the best match
2762 G_FLOAT(OFS_RETURN) = best;
2764 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2765 void PF_getsurfaceclippedpoint(void)
2768 msurface_t *surface;
2770 VectorClear(G_VECTOR(OFS_RETURN));
2771 ed = G_EDICT(OFS_PARM0);
2772 if (!ed || ed->e->free)
2774 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2776 // FIXME: implement rotation/scaling
2777 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2778 clippointtosurface(surface, p, out);
2779 // FIXME: implement rotation/scaling
2780 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2783 #define MAX_PRFILES 256
2785 qfile_t *pr_files[MAX_PRFILES];
2787 void PR_Files_Init(void)
2789 memset(pr_files, 0, sizeof(pr_files));
2792 void PR_Files_CloseAll(void)
2795 for (i = 0;i < MAX_PRFILES;i++)
2798 FS_Close(pr_files[i]);
2803 //float(string s) stof = #81; // get numerical value from a string
2806 char string[STRINGTEMP_LENGTH];
2807 PF_VarString(0, string, sizeof(string));
2808 G_FLOAT(OFS_RETURN) = atof(string);
2811 //float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
2815 char *modestring, *filename;
2816 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2817 if (pr_files[filenum] == NULL)
2819 if (filenum >= MAX_PRFILES)
2821 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2822 G_FLOAT(OFS_RETURN) = -2;
2825 mode = G_FLOAT(OFS_PARM1);
2828 case 0: // FILE_READ
2831 case 1: // FILE_APPEND
2834 case 2: // FILE_WRITE
2838 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2839 G_FLOAT(OFS_RETURN) = -3;
2842 filename = G_STRING(OFS_PARM0);
2843 // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2844 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false, false);
2846 if (pr_files[filenum] == NULL && modestring == "rb")
2847 pr_files[filenum] = FS_Open(filename, modestring, false, false);
2849 if (pr_files[filenum] == NULL)
2850 G_FLOAT(OFS_RETURN) = -1;
2852 G_FLOAT(OFS_RETURN) = filenum;
2855 //void(float fhandle) fclose = #111; // closes a file
2856 void PF_fclose(void)
2858 int filenum = G_FLOAT(OFS_PARM0);
2859 if (filenum < 0 || filenum >= MAX_PRFILES)
2861 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2864 if (pr_files[filenum] == NULL)
2866 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2869 FS_Close(pr_files[filenum]);
2870 pr_files[filenum] = NULL;
2873 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2877 static char string[STRINGTEMP_LENGTH];
2878 int filenum = G_FLOAT(OFS_PARM0);
2879 if (filenum < 0 || filenum >= MAX_PRFILES)
2881 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2884 if (pr_files[filenum] == NULL)
2886 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2892 c = FS_Getc(pr_files[filenum]);
2893 if (c == '\r' || c == '\n' || c < 0)
2895 if (end < STRINGTEMP_LENGTH - 1)
2899 // remove \n following \r
2902 c = FS_Getc(pr_files[filenum]);
2904 FS_UnGetc(pr_files[filenum], (unsigned char)c);
2906 if (developer.integer)
2907 Con_Printf("fgets: %s\n", string);
2909 G_INT(OFS_RETURN) = PR_SetString(string);
2911 G_INT(OFS_RETURN) = 0;
2914 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2918 char string[STRINGTEMP_LENGTH];
2919 int filenum = G_FLOAT(OFS_PARM0);
2920 if (filenum < 0 || filenum >= MAX_PRFILES)
2922 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2925 if (pr_files[filenum] == NULL)
2927 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2930 PF_VarString(1, string, sizeof(string));
2931 if ((stringlength = strlen(string)))
2932 FS_Write(pr_files[filenum], string, stringlength);
2933 if (developer.integer)
2934 Con_Printf("fputs: %s\n", string);
2937 //float(string s) strlen = #114; // returns how many characters are in a string
2938 void PF_strlen(void)
2941 s = G_STRING(OFS_PARM0);
2943 G_FLOAT(OFS_RETURN) = strlen(s);
2945 G_FLOAT(OFS_RETURN) = 0;
2948 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2949 void PF_strcat(void)
2951 char *s = PR_GetTempString();
2952 PF_VarString(0, s, STRINGTEMP_LENGTH);
2953 G_INT(OFS_RETURN) = PR_SetString(s);
2956 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2957 void PF_substring(void)
2959 int i, start, length;
2960 char *s, *string = PR_GetTempString();
2961 s = G_STRING(OFS_PARM0);
2962 start = G_FLOAT(OFS_PARM1);
2963 length = G_FLOAT(OFS_PARM2);
2966 for (i = 0;i < start && *s;i++, s++);
2967 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2970 G_INT(OFS_RETURN) = PR_SetString(string);
2973 //vector(string s) stov = #117; // returns vector value from a string
2976 char string[STRINGTEMP_LENGTH];
2977 PF_VarString(0, string, sizeof(string));
2978 Math_atov(string, G_VECTOR(OFS_RETURN));
2981 //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
2982 void PF_strzone(void)
2985 in = G_STRING(OFS_PARM0);
2986 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2988 G_INT(OFS_RETURN) = PR_SetString(out);
2991 //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
2992 void PF_strunzone(void)
2994 Mem_Free(G_STRING(OFS_PARM0));
2997 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2998 //this function originally written by KrimZon, made shorter by LordHavoc
2999 void PF_clientcommand (void)
3001 client_t *temp_client;
3004 //find client for this entity
3005 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3006 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3008 Con_Print("PF_clientcommand: entity is not a client\n");
3012 temp_client = host_client;
3013 host_client = svs.clients + i;
3014 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3015 host_client = temp_client;
3018 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3019 //this function originally written by KrimZon, made shorter by LordHavoc
3020 //20040203: rewritten by LordHavoc (no longer uses allocations)
3022 char *tokens[256], tokenbuf[4096];
3023 void PF_tokenize (void)
3027 p = G_STRING(OFS_PARM0);
3031 while(COM_ParseToken(&p, false))
3033 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3035 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3037 tokens[num_tokens++] = tokenbuf + pos;
3038 strcpy(tokenbuf + pos, com_token);
3039 pos += strlen(com_token) + 1;
3042 G_FLOAT(OFS_RETURN) = num_tokens;
3045 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3046 //this function originally written by KrimZon, made shorter by LordHavoc
3049 int token_num = G_FLOAT(OFS_PARM0);
3050 if (token_num >= 0 && token_num < num_tokens)
3051 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3053 G_INT(OFS_RETURN) = PR_SetString("");
3056 //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)
3057 void PF_setattachment (void)
3059 edict_t *e = G_EDICT(OFS_PARM0);
3060 edict_t *tagentity = G_EDICT(OFS_PARM1);
3061 char *tagname = G_STRING(OFS_PARM2);
3067 PF_WARNING("setattachment: can not modify world entity\n");
3069 PF_WARNING("setattachment: can not modify free entity\n");
3071 if (tagentity == NULL)
3072 tagentity = sv.edicts;
3074 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3076 v->edict = EDICT_TO_PROG(tagentity);
3078 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3081 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3083 modelindex = (int)tagentity->v->modelindex;
3084 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3086 v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->v->skin, tagname);
3088 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", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
3091 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
3095 /////////////////////////////////////////
3096 // DP_MD3_TAGINFO extension coded by VorteX
3098 int SV_GetTagIndex (edict_t *e, char *tagname)
3103 i = e->v->modelindex;
3104 if (i < 1 || i >= MAX_MODELS)
3106 model = sv.models[i];
3108 return Mod_Alias_GetTagIndexForName(model, e->v->skin, tagname);
3111 // Warnings/errors code:
3112 // 0 - normal (everything all-right)
3115 // 3 - null or non-precached model
3116 // 4 - no tags with requested index
3117 // 5 - runaway loop at attachment chain
3118 extern cvar_t cl_bob;
3119 extern cvar_t cl_bobcycle;
3120 extern cvar_t cl_bobup;
3121 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3124 int modelindex, reqframe, attachloop;
3125 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3129 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3131 if (ent == sv.edicts)
3136 modelindex = (int)ent->v->modelindex;
3137 if (modelindex <= 0 || modelindex > MAX_MODELS)
3140 model = sv.models[modelindex];
3142 if (ent->v->frame >= 0 && ent->v->frame < model->numframes && model->animscenes)
3143 reqframe = model->animscenes[(int)ent->v->frame].firstframe;
3145 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3147 // get initial tag matrix
3150 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
3155 Matrix4x4_CreateIdentity(&tagmatrix);
3157 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3158 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3162 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3163 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3164 if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS && (model = sv.models[(int)attachent->v->modelindex]) && model->animscenes && attachent->v->frame >= 0 && attachent->v->frame < model->numframes)
3165 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->v->frame].firstframe, val->_float - 1, &attachmatrix);
3167 Matrix4x4_CreateIdentity(&attachmatrix);
3169 // apply transformation by child entity matrix
3170 val = GETEDICTFIELDVALUE(ent, eval_scale);
3171 if (val->_float == 0)
3173 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], -ent->v->angles[0], ent->v->angles[1], ent->v->angles[2], val->_float);
3174 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3175 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3176 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3177 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3178 Matrix4x4_Copy(&tagmatrix, out);
3180 // finally transformate by matrix of tag on parent entity
3181 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3182 out->m[0][3] = attachmatrix.m[0][3] + attachmatrix.m[0][0]*tagmatrix.m[0][3] + attachmatrix.m[0][1]*tagmatrix.m[1][3] + attachmatrix.m[0][2]*tagmatrix.m[2][3];
3183 out->m[1][3] = attachmatrix.m[1][3] + attachmatrix.m[1][0]*tagmatrix.m[0][3] + attachmatrix.m[1][1]*tagmatrix.m[1][3] + attachmatrix.m[1][2]*tagmatrix.m[2][3];
3184 out->m[2][3] = attachmatrix.m[2][3] + attachmatrix.m[2][0]*tagmatrix.m[0][3] + attachmatrix.m[2][1]*tagmatrix.m[1][3] + attachmatrix.m[2][2]*tagmatrix.m[2][3];
3185 Matrix4x4_Copy(&tagmatrix, out);
3189 if (attachloop > 255) // prevent runaway looping
3192 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3195 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3196 val = GETEDICTFIELDVALUE(ent, eval_scale);
3197 if (val->_float == 0)
3199 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3200 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], -ent->v->angles[0], ent->v->angles[1], ent->v->angles[2], val->_float);
3201 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3202 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3203 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3204 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3206 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3207 {// RENDER_VIEWMODEL magic
3208 Matrix4x4_Copy(&tagmatrix, out);
3209 ent = EDICT_NUM(val->edict);
3211 val = GETEDICTFIELDVALUE(ent, eval_scale);
3212 if (val->_float == 0)
3215 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] + ent->v->view_ofs[2], ent->v->v_angle[0], ent->v->v_angle[1], ent->v->v_angle[2], val->_float);
3216 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3217 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3218 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3219 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3222 // Cl_bob, ported from rendering code
3223 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3226 // LordHavoc: this code is *weird*, but not replacable (I think it
3227 // should be done in QC on the server, but oh well, quake is quake)
3228 // LordHavoc: figured out bobup: the time at which the sin is at 180
3229 // degrees (which allows lengthening or squishing the peak or valley)
3230 cycle = sv.time/cl_bobcycle.value;
3231 cycle -= (int)cycle;
3232 if (cycle < cl_bobup.value)
3233 cycle = sin(M_PI * cycle / cl_bobup.value);
3235 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3236 // bob is proportional to velocity in the xy plane
3237 // (don't count Z, or jumping messes it up)
3238 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3239 bob = bob*0.3 + bob*0.7*cycle;
3240 out->m[2][3] += bound(-7, bob, 4);
3247 //float(entity ent, string tagname) gettagindex;
3249 void PF_gettagindex (void)
3251 edict_t *ent = G_EDICT(OFS_PARM0);
3252 char *tag_name = G_STRING(OFS_PARM1);
3253 int modelindex, tag_index;
3255 if (ent == sv.edicts)
3256 PF_WARNING("gettagindex: can't affect world entity\n");
3258 PF_WARNING("gettagindex: can't affect free entity\n");
3260 modelindex = (int)ent->v->modelindex;
3262 if (modelindex <= 0 || modelindex > MAX_MODELS)
3263 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3266 tag_index = SV_GetTagIndex(ent, tag_name);
3268 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3270 G_FLOAT(OFS_RETURN) = tag_index;
3273 //vector(entity ent, float tagindex) gettaginfo;
3274 void PF_gettaginfo (void)
3276 edict_t *e = G_EDICT(OFS_PARM0);
3277 int tagindex = (int)G_FLOAT(OFS_PARM1);
3278 matrix4x4_t tag_matrix;
3281 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3282 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3287 PF_WARNING("gettagindex: can't affect world entity\n");
3290 PF_WARNING("gettagindex: can't affect free entity\n");
3293 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3296 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3299 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3305 /////////////////////////////////////////
3306 // DP_QC_FS_SEARCH extension
3308 // qc fs search handling
3309 #define MAX_SEARCHES 128
3311 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3313 void PR_Search_Init(void)
3315 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3318 void PR_Search_Reset(void)
3321 // reset the fssearch list
3322 for(i = 0; i < MAX_SEARCHES; i++)
3323 if(pr_fssearchlist[i])
3324 FS_FreeSearch(pr_fssearchlist[i]);
3325 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3332 float search_begin(string pattern, float caseinsensitive, float quiet)
3335 void PF_search_begin(void)
3339 int caseinsens, quiet;
3341 pattern = G_STRING(OFS_PARM0);
3343 PR_CheckEmptyString(pattern);
3345 caseinsens = G_FLOAT(OFS_PARM1);
3346 quiet = G_FLOAT(OFS_PARM2);
3348 for(handle = 0; handle < MAX_SEARCHES; handle++)
3349 if(!pr_fssearchlist[handle])
3352 if(handle >= MAX_SEARCHES)
3354 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3355 G_FLOAT(OFS_RETURN) = -2;
3359 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3360 G_FLOAT(OFS_RETURN) = -1;
3362 G_FLOAT(OFS_RETURN) = handle;
3369 void search_end(float handle)
3372 void PF_search_end(void)
3376 handle = G_FLOAT(OFS_PARM0);
3378 if(handle < 0 || handle >= MAX_SEARCHES)
3380 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3383 if(pr_fssearchlist[handle] == NULL)
3385 Con_Printf("PF_search_end: no such handle %i\n", handle);
3389 FS_FreeSearch(pr_fssearchlist[handle]);
3390 pr_fssearchlist[handle] = NULL;
3397 float search_getsize(float handle)
3400 void PF_search_getsize(void)
3404 handle = G_FLOAT(OFS_PARM0);
3406 if(handle < 0 || handle >= MAX_SEARCHES)
3408 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3411 if(pr_fssearchlist[handle] == NULL)
3413 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3417 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3422 VM_search_getfilename
3424 string search_getfilename(float handle, float num)
3427 void PF_search_getfilename(void)
3429 int handle, filenum;
3432 handle = G_FLOAT(OFS_PARM0);
3433 filenum = G_FLOAT(OFS_PARM1);
3435 if(handle < 0 || handle >= MAX_SEARCHES)
3437 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3440 if(pr_fssearchlist[handle] == NULL)
3442 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3445 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3447 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3451 tmp = PR_GetTempString();
3452 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3454 G_INT(OFS_RETURN) = PR_SetString(tmp);
3457 void PF_cvar_string (void)
3463 str = G_STRING(OFS_PARM0);
3464 var = Cvar_FindVar (str);
3467 tmp = PR_GetTempString();
3468 strcpy(tmp, var->string);
3472 G_INT(OFS_RETURN) = PR_SetString(tmp);
3475 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3476 void PF_dropclient (void)
3479 client_t *oldhostclient;
3480 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3481 if (clientnum < 0 || clientnum >= svs.maxclients)
3482 PF_WARNING("dropclient: not a client\n");
3483 if (!svs.clients[clientnum].active)
3484 PF_WARNING("dropclient: that client slot is not connected\n");
3485 oldhostclient = host_client;
3486 host_client = svs.clients + clientnum;
3487 SV_DropClient(false);
3488 host_client = oldhostclient;
3491 //entity() spawnclient (DP_SV_BOTCLIENT)
3492 void PF_spawnclient (void)
3496 pr_xfunction->builtinsprofile += 2;
3498 for (i = 0;i < svs.maxclients;i++)
3500 if (!svs.clients[i].active)
3502 pr_xfunction->builtinsprofile += 100;
3503 SV_ConnectClient (i, NULL);
3504 ed = EDICT_NUM(i + 1);
3511 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3512 void PF_clienttype (void)
3515 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3516 if (clientnum < 0 || clientnum >= svs.maxclients)
3517 G_FLOAT(OFS_RETURN) = 3;
3518 else if (!svs.clients[clientnum].active)
3519 G_FLOAT(OFS_RETURN) = 0;
3520 else if (svs.clients[clientnum].netconnection)
3521 G_FLOAT(OFS_RETURN) = 1;
3523 G_FLOAT(OFS_RETURN) = 2;
3526 builtin_t pr_builtin[] =
3529 PF_makevectors, // #1 void(entity e) makevectors
3530 PF_setorigin, // #2 void(entity e, vector o) setorigin
3531 PF_setmodel, // #3 void(entity e, string m) setmodel
3532 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3533 NULL, // #5 void(entity e, vector min, vector max) setabssize
3534 PF_break, // #6 void() break
3535 PF_random, // #7 float() random
3536 PF_sound, // #8 void(entity e, float chan, string samp) sound
3537 PF_normalize, // #9 vector(vector v) normalize
3538 PF_error, // #10 void(string e) error
3539 PF_objerror, // #11 void(string e) objerror
3540 PF_vlen, // #12 float(vector v) vlen
3541 PF_vectoyaw, // #13 float(vector v) vectoyaw
3542 PF_Spawn, // #14 entity() spawn
3543 PF_Remove, // #15 void(entity e) remove
3544 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3545 PF_checkclient, // #17 entity() clientlist
3546 PF_Find, // #18 entity(entity start, .string fld, string match) find
3547 PF_precache_sound, // #19 void(string s) precache_sound
3548 PF_precache_model, // #20 void(string s) precache_model
3549 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3550 PF_findradius, // #22 entity(vector org, float rad) findradius
3551 PF_bprint, // #23 void(string s) bprint
3552 PF_sprint, // #24 void(entity client, string s) sprint
3553 PF_dprint, // #25 void(string s) dprint
3554 PF_ftos, // #26 void(string s) ftos
3555 PF_vtos, // #27 void(string s) vtos
3556 PF_coredump, // #28 void() coredump
3557 PF_traceon, // #29 void() traceon
3558 PF_traceoff, // #30 void() traceoff
3559 PF_eprint, // #31 void(entity e) eprint
3560 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3562 PF_droptofloor, // #34 float() droptofloor
3563 PF_lightstyle, // #35 void(float style, string value) lightstyle
3564 PF_rint, // #36 float(float v) rint
3565 PF_floor, // #37 float(float v) floor
3566 PF_ceil, // #38 float(float v) ceil
3568 PF_checkbottom, // #40 float(entity e) checkbottom
3569 PF_pointcontents, // #41 float(vector v) pointcontents
3571 PF_fabs, // #43 float(float f) fabs
3572 PF_aim, // #44 vector(entity e, float speed) aim
3573 PF_cvar, // #45 float(string s) cvar
3574 PF_localcmd, // #46 void(string s) localcmd
3575 PF_nextent, // #47 entity(entity e) nextent
3576 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3577 PF_changeyaw, // #49 void() ChangeYaw
3579 PF_vectoangles, // #51 vector(vector v) vectoangles
3580 PF_WriteByte, // #52 void(float to, float f) WriteByte
3581 PF_WriteChar, // #53 void(float to, float f) WriteChar
3582 PF_WriteShort, // #54 void(float to, float f) WriteShort
3583 PF_WriteLong, // #55 void(float to, float f) WriteLong
3584 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3585 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3586 PF_WriteString, // #58 void(float to, string s) WriteString
3587 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3588 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3589 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3590 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3591 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3592 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3593 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3595 SV_MoveToGoal, // #67 void(float step) movetogoal
3596 PF_precache_file, // #68 string(string s) precache_file
3597 PF_makestatic, // #69 void(entity e) makestatic
3598 PF_changelevel, // #70 void(string s) changelevel
3600 PF_cvar_set, // #72 void(string var, string val) cvar_set
3601 PF_centerprint, // #73 void(entity client, strings) centerprint
3602 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3603 PF_precache_model, // #75 string(string s) precache_model2
3604 PF_precache_sound, // #76 string(string s) precache_sound2
3605 PF_precache_file, // #77 string(string s) precache_file2
3606 PF_setspawnparms, // #78 void(entity e) setspawnparms
3609 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3618 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3619 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3620 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3621 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3622 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3623 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3624 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3625 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3626 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3627 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3638 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3639 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3640 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3641 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3642 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3643 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3644 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3645 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3646 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3647 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3648 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3649 a a a a a a a a // #120-199
3650 a a a a a a a a a a // #200-299
3651 a a a a a a a a a a // #300-399
3652 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3653 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3654 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3655 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3656 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3657 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3658 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3659 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3660 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3661 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3662 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3663 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3664 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3665 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3666 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3667 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3668 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3669 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3670 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3671 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3672 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3673 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3674 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3675 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3676 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3677 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3678 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3679 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3680 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3681 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3682 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3683 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3684 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3685 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3686 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3687 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3688 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3689 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3690 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3691 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3692 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3693 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3694 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3695 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3696 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3697 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3698 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3699 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3700 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3701 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3702 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3703 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3704 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3705 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3706 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3707 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3712 a a a a // #460-499 (LordHavoc)
3715 builtin_t *pr_builtins = pr_builtin;
3716 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3718 void PR_Cmd_Init(void)
3720 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3725 void PR_Cmd_Shutdown(void)
3727 Mem_FreePool (&pr_strings_mempool);
3730 void PR_Cmd_Reset(void)
3732 Mem_EmptyPool(pr_strings_mempool);
3734 PR_Files_CloseAll();