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;
2609 bestdist = 1000000000;
2611 for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2613 // clip original point to each triangle of the surface and find the
2614 // triangle that is closest
2615 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
2616 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
2617 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
2618 TriangleNormal(v[0], v[1], v[2], facenormal);
2619 VectorNormalize(facenormal);
2620 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2621 VectorMA(p, offsetdist, facenormal, temp);
2622 for (j = 0, k = 2;j < 3;k = j, j++)
2624 VectorSubtract(v[k], v[j], edgenormal);
2625 CrossProduct(edgenormal, facenormal, sidenormal);
2626 VectorNormalize(sidenormal);
2627 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2629 VectorMA(temp, offsetdist, sidenormal, temp);
2631 dist = VectorDistance2(temp, p);
2632 if (bestdist > dist)
2635 VectorCopy(temp, out);
2640 static msurface_t *getsurface(edict_t *ed, int surfacenum)
2644 if (!ed || ed->e->free)
2646 modelindex = ed->v->modelindex;
2647 if (modelindex < 1 || modelindex >= MAX_MODELS)
2649 model = sv.models[modelindex];
2650 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2652 return model->brush.data_surfaces + surfacenum + model->firstmodelsurface;
2656 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2657 void PF_getsurfacenumpoints(void)
2659 msurface_t *surface;
2660 // return 0 if no such surface
2661 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2663 G_FLOAT(OFS_RETURN) = 0;
2667 // note: this (incorrectly) assumes it is a simple polygon
2668 G_FLOAT(OFS_RETURN) = surface->num_vertices;
2670 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2671 void PF_getsurfacepoint(void)
2674 msurface_t *surface;
2676 VectorClear(G_VECTOR(OFS_RETURN));
2677 ed = G_EDICT(OFS_PARM0);
2678 if (!ed || ed->e->free)
2680 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2682 // note: this (incorrectly) assumes it is a simple polygon
2683 pointnum = G_FLOAT(OFS_PARM2);
2684 if (pointnum < 0 || pointnum >= surface->num_vertices)
2686 // FIXME: implement rotation/scaling
2687 VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2689 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2690 void PF_getsurfacenormal(void)
2692 msurface_t *surface;
2694 VectorClear(G_VECTOR(OFS_RETURN));
2695 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2697 // FIXME: implement rotation/scaling
2698 // note: this (incorrectly) assumes it is a simple polygon
2699 // note: this only returns the first triangle, so it doesn't work very
2700 // well for curved surfaces or arbitrary meshes
2701 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);
2702 VectorNormalize(normal);
2703 VectorCopy(normal, G_VECTOR(OFS_RETURN));
2705 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2706 void PF_getsurfacetexture(void)
2708 msurface_t *surface;
2709 G_INT(OFS_RETURN) = 0;
2710 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2712 G_INT(OFS_RETURN) = PR_SetString(surface->texture->name);
2714 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2715 void PF_getsurfacenearpoint(void)
2717 int surfacenum, best, modelindex;
2719 vec_t dist, bestdist;
2722 msurface_t *surface;
2724 G_FLOAT(OFS_RETURN) = -1;
2725 ed = G_EDICT(OFS_PARM0);
2726 point = G_VECTOR(OFS_PARM1);
2728 if (!ed || ed->e->free)
2730 modelindex = ed->v->modelindex;
2731 if (modelindex < 1 || modelindex >= MAX_MODELS)
2733 model = sv.models[modelindex];
2734 if (!model->brush.num_surfaces)
2737 // FIXME: implement rotation/scaling
2738 VectorSubtract(point, ed->v->origin, p);
2740 bestdist = 1000000000;
2741 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2743 surface = model->brush.data_surfaces + surfacenum + model->firstmodelsurface;
2744 // first see if the nearest point on the surface's box is closer than the previous match
2745 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2746 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2747 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2748 dist = VectorLength2(clipped);
2749 if (dist < bestdist)
2751 // it is, check the nearest point on the actual geometry
2752 clippointtosurface(surface, p, clipped);
2753 VectorSubtract(clipped, p, clipped);
2754 dist += VectorLength2(clipped);
2755 if (dist < bestdist)
2757 // that's closer too, store it as the best match
2763 G_FLOAT(OFS_RETURN) = best;
2765 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2766 void PF_getsurfaceclippedpoint(void)
2769 msurface_t *surface;
2771 VectorClear(G_VECTOR(OFS_RETURN));
2772 ed = G_EDICT(OFS_PARM0);
2773 if (!ed || ed->e->free)
2775 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2777 // FIXME: implement rotation/scaling
2778 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2779 clippointtosurface(surface, p, out);
2780 // FIXME: implement rotation/scaling
2781 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2784 #define MAX_PRFILES 256
2786 qfile_t *pr_files[MAX_PRFILES];
2788 void PR_Files_Init(void)
2790 memset(pr_files, 0, sizeof(pr_files));
2793 void PR_Files_CloseAll(void)
2796 for (i = 0;i < MAX_PRFILES;i++)
2799 FS_Close(pr_files[i]);
2804 //float(string s) stof = #81; // get numerical value from a string
2807 char string[STRINGTEMP_LENGTH];
2808 PF_VarString(0, string, sizeof(string));
2809 G_FLOAT(OFS_RETURN) = atof(string);
2812 //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
2816 char *modestring, *filename;
2817 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2818 if (pr_files[filenum] == NULL)
2820 if (filenum >= MAX_PRFILES)
2822 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2823 G_FLOAT(OFS_RETURN) = -2;
2826 mode = G_FLOAT(OFS_PARM1);
2829 case 0: // FILE_READ
2832 case 1: // FILE_APPEND
2835 case 2: // FILE_WRITE
2839 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2840 G_FLOAT(OFS_RETURN) = -3;
2843 filename = G_STRING(OFS_PARM0);
2844 // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2845 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false, false);
2847 if (pr_files[filenum] == NULL && modestring == "rb")
2848 pr_files[filenum] = FS_Open(filename, modestring, false, false);
2850 if (pr_files[filenum] == NULL)
2851 G_FLOAT(OFS_RETURN) = -1;
2853 G_FLOAT(OFS_RETURN) = filenum;
2856 //void(float fhandle) fclose = #111; // closes a file
2857 void PF_fclose(void)
2859 int filenum = G_FLOAT(OFS_PARM0);
2860 if (filenum < 0 || filenum >= MAX_PRFILES)
2862 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2865 if (pr_files[filenum] == NULL)
2867 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2870 FS_Close(pr_files[filenum]);
2871 pr_files[filenum] = NULL;
2874 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2878 static char string[STRINGTEMP_LENGTH];
2879 int filenum = G_FLOAT(OFS_PARM0);
2880 if (filenum < 0 || filenum >= MAX_PRFILES)
2882 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2885 if (pr_files[filenum] == NULL)
2887 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2893 c = FS_Getc(pr_files[filenum]);
2894 if (c == '\r' || c == '\n' || c < 0)
2896 if (end < STRINGTEMP_LENGTH - 1)
2900 // remove \n following \r
2903 c = FS_Getc(pr_files[filenum]);
2905 FS_UnGetc(pr_files[filenum], (unsigned char)c);
2907 if (developer.integer)
2908 Con_Printf("fgets: %s\n", string);
2910 G_INT(OFS_RETURN) = PR_SetString(string);
2912 G_INT(OFS_RETURN) = 0;
2915 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2919 char string[STRINGTEMP_LENGTH];
2920 int filenum = G_FLOAT(OFS_PARM0);
2921 if (filenum < 0 || filenum >= MAX_PRFILES)
2923 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2926 if (pr_files[filenum] == NULL)
2928 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2931 PF_VarString(1, string, sizeof(string));
2932 if ((stringlength = strlen(string)))
2933 FS_Write(pr_files[filenum], string, stringlength);
2934 if (developer.integer)
2935 Con_Printf("fputs: %s\n", string);
2938 //float(string s) strlen = #114; // returns how many characters are in a string
2939 void PF_strlen(void)
2942 s = G_STRING(OFS_PARM0);
2944 G_FLOAT(OFS_RETURN) = strlen(s);
2946 G_FLOAT(OFS_RETURN) = 0;
2949 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2950 void PF_strcat(void)
2952 char *s = PR_GetTempString();
2953 PF_VarString(0, s, STRINGTEMP_LENGTH);
2954 G_INT(OFS_RETURN) = PR_SetString(s);
2957 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2958 void PF_substring(void)
2960 int i, start, length;
2961 char *s, *string = PR_GetTempString();
2962 s = G_STRING(OFS_PARM0);
2963 start = G_FLOAT(OFS_PARM1);
2964 length = G_FLOAT(OFS_PARM2);
2967 for (i = 0;i < start && *s;i++, s++);
2968 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2971 G_INT(OFS_RETURN) = PR_SetString(string);
2974 //vector(string s) stov = #117; // returns vector value from a string
2977 char string[STRINGTEMP_LENGTH];
2978 PF_VarString(0, string, sizeof(string));
2979 Math_atov(string, G_VECTOR(OFS_RETURN));
2982 //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)
2983 void PF_strzone(void)
2986 in = G_STRING(OFS_PARM0);
2987 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2989 G_INT(OFS_RETURN) = PR_SetString(out);
2992 //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!!!)
2993 void PF_strunzone(void)
2995 Mem_Free(G_STRING(OFS_PARM0));
2998 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2999 //this function originally written by KrimZon, made shorter by LordHavoc
3000 void PF_clientcommand (void)
3002 client_t *temp_client;
3005 //find client for this entity
3006 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3007 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3009 Con_Print("PF_clientcommand: entity is not a client\n");
3013 temp_client = host_client;
3014 host_client = svs.clients + i;
3015 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3016 host_client = temp_client;
3019 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3020 //this function originally written by KrimZon, made shorter by LordHavoc
3021 //20040203: rewritten by LordHavoc (no longer uses allocations)
3023 char *tokens[256], tokenbuf[4096];
3024 void PF_tokenize (void)
3028 p = G_STRING(OFS_PARM0);
3032 while(COM_ParseToken(&p, false))
3034 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3036 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3038 tokens[num_tokens++] = tokenbuf + pos;
3039 strcpy(tokenbuf + pos, com_token);
3040 pos += strlen(com_token) + 1;
3043 G_FLOAT(OFS_RETURN) = num_tokens;
3046 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3047 //this function originally written by KrimZon, made shorter by LordHavoc
3050 int token_num = G_FLOAT(OFS_PARM0);
3051 if (token_num >= 0 && token_num < num_tokens)
3052 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3054 G_INT(OFS_RETURN) = PR_SetString("");
3057 //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)
3058 void PF_setattachment (void)
3060 edict_t *e = G_EDICT(OFS_PARM0);
3061 edict_t *tagentity = G_EDICT(OFS_PARM1);
3062 char *tagname = G_STRING(OFS_PARM2);
3068 PF_WARNING("setattachment: can not modify world entity\n");
3070 PF_WARNING("setattachment: can not modify free entity\n");
3072 if (tagentity == NULL)
3073 tagentity = sv.edicts;
3075 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3077 v->edict = EDICT_TO_PROG(tagentity);
3079 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3082 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3084 modelindex = (int)tagentity->v->modelindex;
3085 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3087 v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->v->skin, tagname);
3089 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);
3092 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));
3096 /////////////////////////////////////////
3097 // DP_MD3_TAGINFO extension coded by VorteX
3099 int SV_GetTagIndex (edict_t *e, char *tagname)
3104 i = e->v->modelindex;
3105 if (i < 1 || i >= MAX_MODELS)
3107 model = sv.models[i];
3109 return Mod_Alias_GetTagIndexForName(model, e->v->skin, tagname);
3112 // Warnings/errors code:
3113 // 0 - normal (everything all-right)
3116 // 3 - null or non-precached model
3117 // 4 - no tags with requested index
3118 // 5 - runaway loop at attachment chain
3119 extern cvar_t cl_bob;
3120 extern cvar_t cl_bobcycle;
3121 extern cvar_t cl_bobup;
3122 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3125 int modelindex, reqframe, attachloop;
3126 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3130 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3132 if (ent == sv.edicts)
3137 modelindex = (int)ent->v->modelindex;
3138 if (modelindex <= 0 || modelindex > MAX_MODELS)
3141 model = sv.models[modelindex];
3143 if (ent->v->frame >= 0 && ent->v->frame < model->numframes && model->animscenes)
3144 reqframe = model->animscenes[(int)ent->v->frame].firstframe;
3146 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3148 // get initial tag matrix
3151 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
3156 Matrix4x4_CreateIdentity(&tagmatrix);
3158 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3159 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3163 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3164 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3165 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)
3166 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->v->frame].firstframe, val->_float - 1, &attachmatrix);
3168 Matrix4x4_CreateIdentity(&attachmatrix);
3170 // apply transformation by child entity matrix
3171 val = GETEDICTFIELDVALUE(ent, eval_scale);
3172 if (val->_float == 0)
3174 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);
3175 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3176 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]);
3177 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]);
3178 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]);
3179 Matrix4x4_Copy(&tagmatrix, out);
3181 // finally transformate by matrix of tag on parent entity
3182 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3183 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];
3184 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];
3185 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];
3186 Matrix4x4_Copy(&tagmatrix, out);
3190 if (attachloop > 255) // prevent runaway looping
3193 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3196 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3197 val = GETEDICTFIELDVALUE(ent, eval_scale);
3198 if (val->_float == 0)
3200 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3201 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);
3202 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3203 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]);
3204 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]);
3205 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]);
3207 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3208 {// RENDER_VIEWMODEL magic
3209 Matrix4x4_Copy(&tagmatrix, out);
3210 ent = EDICT_NUM(val->edict);
3212 val = GETEDICTFIELDVALUE(ent, eval_scale);
3213 if (val->_float == 0)
3216 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);
3217 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3218 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]);
3219 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]);
3220 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]);
3223 // Cl_bob, ported from rendering code
3224 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3227 // LordHavoc: this code is *weird*, but not replacable (I think it
3228 // should be done in QC on the server, but oh well, quake is quake)
3229 // LordHavoc: figured out bobup: the time at which the sin is at 180
3230 // degrees (which allows lengthening or squishing the peak or valley)
3231 cycle = sv.time/cl_bobcycle.value;
3232 cycle -= (int)cycle;
3233 if (cycle < cl_bobup.value)
3234 cycle = sin(M_PI * cycle / cl_bobup.value);
3236 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3237 // bob is proportional to velocity in the xy plane
3238 // (don't count Z, or jumping messes it up)
3239 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3240 bob = bob*0.3 + bob*0.7*cycle;
3241 out->m[2][3] += bound(-7, bob, 4);
3248 //float(entity ent, string tagname) gettagindex;
3250 void PF_gettagindex (void)
3252 edict_t *ent = G_EDICT(OFS_PARM0);
3253 char *tag_name = G_STRING(OFS_PARM1);
3254 int modelindex, tag_index;
3256 if (ent == sv.edicts)
3257 PF_WARNING("gettagindex: can't affect world entity\n");
3259 PF_WARNING("gettagindex: can't affect free entity\n");
3261 modelindex = (int)ent->v->modelindex;
3263 if (modelindex <= 0 || modelindex > MAX_MODELS)
3264 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3267 tag_index = SV_GetTagIndex(ent, tag_name);
3269 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3271 G_FLOAT(OFS_RETURN) = tag_index;
3274 //vector(entity ent, float tagindex) gettaginfo;
3275 void PF_gettaginfo (void)
3277 edict_t *e = G_EDICT(OFS_PARM0);
3278 int tagindex = (int)G_FLOAT(OFS_PARM1);
3279 matrix4x4_t tag_matrix;
3282 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3283 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3288 PF_WARNING("gettagindex: can't affect world entity\n");
3291 PF_WARNING("gettagindex: can't affect free entity\n");
3294 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3297 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3300 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3306 /////////////////////////////////////////
3307 // DP_QC_FS_SEARCH extension
3309 // qc fs search handling
3310 #define MAX_SEARCHES 128
3312 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3314 void PR_Search_Init(void)
3316 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3319 void PR_Search_Reset(void)
3322 // reset the fssearch list
3323 for(i = 0; i < MAX_SEARCHES; i++)
3324 if(pr_fssearchlist[i])
3325 FS_FreeSearch(pr_fssearchlist[i]);
3326 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3333 float search_begin(string pattern, float caseinsensitive, float quiet)
3336 void PF_search_begin(void)
3340 int caseinsens, quiet;
3342 pattern = G_STRING(OFS_PARM0);
3344 PR_CheckEmptyString(pattern);
3346 caseinsens = G_FLOAT(OFS_PARM1);
3347 quiet = G_FLOAT(OFS_PARM2);
3349 for(handle = 0; handle < MAX_SEARCHES; handle++)
3350 if(!pr_fssearchlist[handle])
3353 if(handle >= MAX_SEARCHES)
3355 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3356 G_FLOAT(OFS_RETURN) = -2;
3360 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3361 G_FLOAT(OFS_RETURN) = -1;
3363 G_FLOAT(OFS_RETURN) = handle;
3370 void search_end(float handle)
3373 void PF_search_end(void)
3377 handle = G_FLOAT(OFS_PARM0);
3379 if(handle < 0 || handle >= MAX_SEARCHES)
3381 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3384 if(pr_fssearchlist[handle] == NULL)
3386 Con_Printf("PF_search_end: no such handle %i\n", handle);
3390 FS_FreeSearch(pr_fssearchlist[handle]);
3391 pr_fssearchlist[handle] = NULL;
3398 float search_getsize(float handle)
3401 void PF_search_getsize(void)
3405 handle = G_FLOAT(OFS_PARM0);
3407 if(handle < 0 || handle >= MAX_SEARCHES)
3409 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3412 if(pr_fssearchlist[handle] == NULL)
3414 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3418 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3423 VM_search_getfilename
3425 string search_getfilename(float handle, float num)
3428 void PF_search_getfilename(void)
3430 int handle, filenum;
3433 handle = G_FLOAT(OFS_PARM0);
3434 filenum = G_FLOAT(OFS_PARM1);
3436 if(handle < 0 || handle >= MAX_SEARCHES)
3438 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3441 if(pr_fssearchlist[handle] == NULL)
3443 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3446 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3448 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3452 tmp = PR_GetTempString();
3453 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3455 G_INT(OFS_RETURN) = PR_SetString(tmp);
3458 void PF_cvar_string (void)
3464 str = G_STRING(OFS_PARM0);
3465 var = Cvar_FindVar (str);
3468 tmp = PR_GetTempString();
3469 strcpy(tmp, var->string);
3473 G_INT(OFS_RETURN) = PR_SetString(tmp);
3476 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3477 void PF_dropclient (void)
3480 client_t *oldhostclient;
3481 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3482 if (clientnum < 0 || clientnum >= svs.maxclients)
3483 PF_WARNING("dropclient: not a client\n");
3484 if (!svs.clients[clientnum].active)
3485 PF_WARNING("dropclient: that client slot is not connected\n");
3486 oldhostclient = host_client;
3487 host_client = svs.clients + clientnum;
3488 SV_DropClient(false);
3489 host_client = oldhostclient;
3492 //entity() spawnclient (DP_SV_BOTCLIENT)
3493 void PF_spawnclient (void)
3497 pr_xfunction->builtinsprofile += 2;
3499 for (i = 0;i < svs.maxclients;i++)
3501 if (!svs.clients[i].active)
3503 pr_xfunction->builtinsprofile += 100;
3504 SV_ConnectClient (i, NULL);
3505 ed = EDICT_NUM(i + 1);
3512 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3513 void PF_clienttype (void)
3516 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3517 if (clientnum < 0 || clientnum >= svs.maxclients)
3518 G_FLOAT(OFS_RETURN) = 3;
3519 else if (!svs.clients[clientnum].active)
3520 G_FLOAT(OFS_RETURN) = 0;
3521 else if (svs.clients[clientnum].netconnection)
3522 G_FLOAT(OFS_RETURN) = 1;
3524 G_FLOAT(OFS_RETURN) = 2;
3527 builtin_t pr_builtin[] =
3530 PF_makevectors, // #1 void(entity e) makevectors
3531 PF_setorigin, // #2 void(entity e, vector o) setorigin
3532 PF_setmodel, // #3 void(entity e, string m) setmodel
3533 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3534 NULL, // #5 void(entity e, vector min, vector max) setabssize
3535 PF_break, // #6 void() break
3536 PF_random, // #7 float() random
3537 PF_sound, // #8 void(entity e, float chan, string samp) sound
3538 PF_normalize, // #9 vector(vector v) normalize
3539 PF_error, // #10 void(string e) error
3540 PF_objerror, // #11 void(string e) objerror
3541 PF_vlen, // #12 float(vector v) vlen
3542 PF_vectoyaw, // #13 float(vector v) vectoyaw
3543 PF_Spawn, // #14 entity() spawn
3544 PF_Remove, // #15 void(entity e) remove
3545 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3546 PF_checkclient, // #17 entity() clientlist
3547 PF_Find, // #18 entity(entity start, .string fld, string match) find
3548 PF_precache_sound, // #19 void(string s) precache_sound
3549 PF_precache_model, // #20 void(string s) precache_model
3550 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3551 PF_findradius, // #22 entity(vector org, float rad) findradius
3552 PF_bprint, // #23 void(string s) bprint
3553 PF_sprint, // #24 void(entity client, string s) sprint
3554 PF_dprint, // #25 void(string s) dprint
3555 PF_ftos, // #26 void(string s) ftos
3556 PF_vtos, // #27 void(string s) vtos
3557 PF_coredump, // #28 void() coredump
3558 PF_traceon, // #29 void() traceon
3559 PF_traceoff, // #30 void() traceoff
3560 PF_eprint, // #31 void(entity e) eprint
3561 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3563 PF_droptofloor, // #34 float() droptofloor
3564 PF_lightstyle, // #35 void(float style, string value) lightstyle
3565 PF_rint, // #36 float(float v) rint
3566 PF_floor, // #37 float(float v) floor
3567 PF_ceil, // #38 float(float v) ceil
3569 PF_checkbottom, // #40 float(entity e) checkbottom
3570 PF_pointcontents, // #41 float(vector v) pointcontents
3572 PF_fabs, // #43 float(float f) fabs
3573 PF_aim, // #44 vector(entity e, float speed) aim
3574 PF_cvar, // #45 float(string s) cvar
3575 PF_localcmd, // #46 void(string s) localcmd
3576 PF_nextent, // #47 entity(entity e) nextent
3577 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3578 PF_changeyaw, // #49 void() ChangeYaw
3580 PF_vectoangles, // #51 vector(vector v) vectoangles
3581 PF_WriteByte, // #52 void(float to, float f) WriteByte
3582 PF_WriteChar, // #53 void(float to, float f) WriteChar
3583 PF_WriteShort, // #54 void(float to, float f) WriteShort
3584 PF_WriteLong, // #55 void(float to, float f) WriteLong
3585 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3586 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3587 PF_WriteString, // #58 void(float to, string s) WriteString
3588 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3589 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3590 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3591 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3592 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3593 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3594 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3596 SV_MoveToGoal, // #67 void(float step) movetogoal
3597 PF_precache_file, // #68 string(string s) precache_file
3598 PF_makestatic, // #69 void(entity e) makestatic
3599 PF_changelevel, // #70 void(string s) changelevel
3601 PF_cvar_set, // #72 void(string var, string val) cvar_set
3602 PF_centerprint, // #73 void(entity client, strings) centerprint
3603 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3604 PF_precache_model, // #75 string(string s) precache_model2
3605 PF_precache_sound, // #76 string(string s) precache_sound2
3606 PF_precache_file, // #77 string(string s) precache_file2
3607 PF_setspawnparms, // #78 void(entity e) setspawnparms
3610 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3619 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3620 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3621 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3622 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3623 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3624 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3625 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3626 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3627 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3628 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3639 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3640 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3641 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3642 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3643 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3644 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3645 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3646 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3647 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3648 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3649 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3650 a a a a a a a a // #120-199
3651 a a a a a a a a a a // #200-299
3652 a a a a a a a a a a // #300-399
3653 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3654 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3655 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3656 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3657 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3658 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3659 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3660 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3661 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3662 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3663 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3664 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3665 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3666 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3667 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3668 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3669 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3670 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3671 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3672 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3673 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3674 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3675 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3676 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3677 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3678 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3679 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3680 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3681 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3682 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3683 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3684 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3685 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3686 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3687 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3688 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3689 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3690 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3691 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3692 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3693 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3694 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3695 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3696 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3697 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3698 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3699 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3700 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3701 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3702 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3703 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3704 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3705 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3706 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3707 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3708 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3713 a a a a // #460-499 (LordHavoc)
3716 builtin_t *pr_builtins = pr_builtin;
3717 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3719 void PR_Cmd_Init(void)
3721 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3726 void PR_Cmd_Shutdown(void)
3728 Mem_FreePool (&pr_strings_mempool);
3731 void PR_Cmd_Reset(void)
3733 Mem_EmptyPool(pr_strings_mempool);
3735 PR_Files_CloseAll();