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 #define MAX_VARSTRING 4096
30 char pr_varstring_temp[MAX_VARSTRING];
32 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
36 ===============================================================================
40 ===============================================================================
44 char *PF_VarString (int first)
50 out = pr_varstring_temp;
51 outend = pr_varstring_temp + sizeof(pr_varstring_temp) - 1;
52 for (i = first;i < pr_argc && out < outend;i++)
54 s = G_STRING((OFS_PARM0+i*3));
55 while (out < outend && *s)
59 return pr_varstring_temp;
62 char *ENGINE_EXTENSIONS =
72 "DP_ENT_CUSTOMCOLORMAP "
73 "DP_ENT_EXTERIORMODELTOCLIENT "
74 "DP_ENT_LOWPRECISION "
78 "DP_GFX_EXTERNALTEXTURES "
80 "DP_GFX_QUAKE3MODELTAGS "
84 "DP_HALFLIFE_MAP_CVAR "
87 "DP_MOVETYPEBOUNCEMISSILE "
93 "DP_QC_FINDCHAINFLOAT "
99 "DP_QC_SINCOSSQRTPOW "
102 "DP_QC_VECTORVECTORS "
108 "DP_SV_DRAWONLYTOCLIENT "
110 "DP_SV_EXTERIORMODELTOCLIENT "
111 "DP_SV_NODRAWTOCLIENT "
112 "DP_SV_PLAYERPHYSICS "
118 "DP_TE_EXPLOSIONRGB "
120 "DP_TE_PARTICLECUBE "
121 "DP_TE_PARTICLERAIN "
122 "DP_TE_PARTICLESNOW "
124 "DP_TE_QUADEFFECTS1 "
127 "DP_TE_STANDARDEFFECTBUILTINS "
130 "KRIMZON_SV_PARSECLIENTCOMMAND "
136 qboolean checkextension(char *name)
141 for (e = ENGINE_EXTENSIONS;*e;e++)
148 while (*e && *e != ' ')
150 if (e - start == len)
151 if (!strncasecmp(start, name, len))
161 returns true if the extension is supported by the server
163 checkextension(extensionname)
166 void PF_checkextension (void)
168 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
175 This is a TERMINAL error, which will kill off the entire server.
187 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
188 ed = PROG_TO_EDICT(pr_global_struct->self);
191 Host_Error ("Program error");
198 Dumps out self, then an error message. The program is aborted and self is
199 removed, but the level can continue.
204 void PF_objerror (void)
210 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
211 ed = PROG_TO_EDICT(pr_global_struct->self);
221 Writes new values for v_forward, v_up, and v_right based on angles
225 void PF_makevectors (void)
227 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
234 Writes new values for v_forward, v_up, and v_right based on the given forward vector
235 vectorvectors(vector, vector)
238 void PF_vectorvectors (void)
240 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
241 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
248 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.
250 setorigin (entity, origin)
253 void PF_setorigin (void)
258 e = G_EDICT(OFS_PARM0);
259 org = G_VECTOR(OFS_PARM1);
260 VectorCopy (org, e->v->origin);
261 SV_LinkEdict (e, false);
265 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
269 for (i=0 ; i<3 ; i++)
271 Host_Error ("backwards mins/maxs");
273 // set derived values
274 VectorCopy (min, e->v->mins);
275 VectorCopy (max, e->v->maxs);
276 VectorSubtract (max, min, e->v->size);
278 SV_LinkEdict (e, false);
285 the size box is rotated by the current angle
286 LordHavoc: no it isn't...
288 setsize (entity, minvector, maxvector)
291 void PF_setsize (void)
296 e = G_EDICT(OFS_PARM0);
297 min = G_VECTOR(OFS_PARM1);
298 max = G_VECTOR(OFS_PARM2);
299 SetMinMaxSize (e, min, max, false);
307 setmodel(entity, model)
310 void PF_setmodel (void)
317 e = G_EDICT(OFS_PARM0);
318 m = G_STRING(OFS_PARM1);
320 // check to see if model was properly precached
321 for (i=0, check = sv.model_precache ; *check ; i++, check++)
322 if (!strcmp(*check, m))
326 Host_Error ("no precache: %s\n", m);
329 e->v->model = PR_SetString(*check);
330 e->v->modelindex = i;
332 mod = sv.models[ (int)e->v->modelindex];
335 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
337 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
344 broadcast print to everyone on server
349 void PF_bprint (void)
354 SV_BroadcastPrintf ("%s", s);
361 single print to a specific client
363 sprint(clientent, value)
366 void PF_sprint (void)
372 entnum = G_EDICTNUM(OFS_PARM0);
375 if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1])
377 Con_Printf ("tried to sprint to a non-client\n");
381 client = svs.connectedclients[entnum-1];
382 MSG_WriteChar(&client->message,svc_print);
383 MSG_WriteString(&client->message, s );
391 single print to a specific client
393 centerprint(clientent, value)
396 void PF_centerprint (void)
402 entnum = G_EDICTNUM(OFS_PARM0);
405 if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1])
407 Con_Printf ("tried to sprint to a non-client\n");
411 client = svs.connectedclients[entnum-1];
412 MSG_WriteChar(&client->message,svc_centerprint);
413 MSG_WriteString(&client->message, s );
421 vector normalize(vector)
424 void PF_normalize (void)
430 value1 = G_VECTOR(OFS_PARM0);
432 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
436 newvalue[0] = newvalue[1] = newvalue[2] = 0;
440 newvalue[0] = value1[0] * new;
441 newvalue[1] = value1[1] * new;
442 newvalue[2] = value1[2] * new;
445 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
460 value1 = G_VECTOR(OFS_PARM0);
462 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
465 G_FLOAT(OFS_RETURN) = new;
472 float vectoyaw(vector)
475 void PF_vectoyaw (void)
480 value1 = G_VECTOR(OFS_PARM0);
482 if (value1[1] == 0 && value1[0] == 0)
486 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
491 G_FLOAT(OFS_RETURN) = yaw;
499 vector vectoangles(vector)
502 void PF_vectoangles (void)
508 value1 = G_VECTOR(OFS_PARM0);
510 if (value1[1] == 0 && value1[0] == 0)
520 // LordHavoc: optimized a bit
523 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
527 else if (value1[1] > 0)
532 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
533 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
538 G_FLOAT(OFS_RETURN+0) = pitch;
539 G_FLOAT(OFS_RETURN+1) = yaw;
540 G_FLOAT(OFS_RETURN+2) = 0;
547 Returns a number from 0<= num < 1
552 void PF_random (void)
556 num = (rand ()&0x7fff) / ((float)0x7fff);
558 G_FLOAT(OFS_RETURN) = num;
565 particle(origin, color, count)
568 void PF_particle (void)
574 org = G_VECTOR(OFS_PARM0);
575 dir = G_VECTOR(OFS_PARM1);
576 color = G_FLOAT(OFS_PARM2);
577 count = G_FLOAT(OFS_PARM3);
578 SV_StartParticle (org, dir, color, count);
588 void PF_ambientsound (void)
593 float vol, attenuation;
594 int i, soundnum, large;
596 pos = G_VECTOR (OFS_PARM0);
597 samp = G_STRING(OFS_PARM1);
598 vol = G_FLOAT(OFS_PARM2);
599 attenuation = G_FLOAT(OFS_PARM3);
601 // check to see if samp was properly precached
602 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
603 if (!strcmp(*check,samp))
608 Con_Printf ("no precache: %s\n", samp);
616 // add an svc_spawnambient command to the level signon packet
619 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
621 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
623 for (i=0 ; i<3 ; i++)
624 MSG_WriteDPCoord(&sv.signon, pos[i]);
627 MSG_WriteShort (&sv.signon, soundnum);
629 MSG_WriteByte (&sv.signon, soundnum);
631 MSG_WriteByte (&sv.signon, vol*255);
632 MSG_WriteByte (&sv.signon, attenuation*64);
640 Each entity can have eight independant sound sources, like voice,
643 Channel 0 is an auto-allocate channel, the others override anything
644 already running on that entity/channel pair.
646 An attenuation of 0 will play full volume everywhere in the level.
647 Larger attenuations will drop off.
659 entity = G_EDICT(OFS_PARM0);
660 channel = G_FLOAT(OFS_PARM1);
661 sample = G_STRING(OFS_PARM2);
662 volume = G_FLOAT(OFS_PARM3) * 255;
663 attenuation = G_FLOAT(OFS_PARM4);
665 if (volume < 0 || volume > 255)
666 Host_Error ("SV_StartSound: volume = %i", volume);
668 if (attenuation < 0 || attenuation > 4)
669 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
671 if (channel < 0 || channel > 7)
672 Host_Error ("SV_StartSound: channel = %i", channel);
674 SV_StartSound (entity, channel, sample, volume, attenuation);
686 Host_Error ("break statement");
693 Used for use tracing and shot targeting
694 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
695 if the tryents flag is set.
697 traceline (vector1, vector2, tryents)
700 void PF_traceline (void)
707 pr_xfunction->builtinsprofile += 30;
709 v1 = G_VECTOR(OFS_PARM0);
710 v2 = G_VECTOR(OFS_PARM1);
711 nomonsters = G_FLOAT(OFS_PARM2);
712 ent = G_EDICT(OFS_PARM3);
714 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
716 pr_global_struct->trace_allsolid = trace.allsolid;
717 pr_global_struct->trace_startsolid = trace.startsolid;
718 pr_global_struct->trace_fraction = trace.fraction;
719 pr_global_struct->trace_inwater = trace.inwater;
720 pr_global_struct->trace_inopen = trace.inopen;
721 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
722 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
723 pr_global_struct->trace_plane_dist = trace.plane.dist;
725 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
727 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
728 // FIXME: add trace_endcontents
736 Used for use tracing and shot targeting
737 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
738 if the tryents flag is set.
740 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
743 // LordHavoc: added this for my own use, VERY useful, similar to traceline
744 void PF_tracebox (void)
746 float *v1, *v2, *m1, *m2;
751 pr_xfunction->builtinsprofile += 30;
753 v1 = G_VECTOR(OFS_PARM0);
754 m1 = G_VECTOR(OFS_PARM1);
755 m2 = G_VECTOR(OFS_PARM2);
756 v2 = G_VECTOR(OFS_PARM3);
757 nomonsters = G_FLOAT(OFS_PARM4);
758 ent = G_EDICT(OFS_PARM5);
760 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
762 pr_global_struct->trace_allsolid = trace.allsolid;
763 pr_global_struct->trace_startsolid = trace.startsolid;
764 pr_global_struct->trace_fraction = trace.fraction;
765 pr_global_struct->trace_inwater = trace.inwater;
766 pr_global_struct->trace_inopen = trace.inopen;
767 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
768 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
769 pr_global_struct->trace_plane_dist = trace.plane.dist;
771 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
773 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
776 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
777 void PF_TraceToss (void)
783 pr_xfunction->builtinsprofile += 600;
785 ent = G_EDICT(OFS_PARM0);
786 ignore = G_EDICT(OFS_PARM1);
788 trace = SV_Trace_Toss (ent, ignore);
790 pr_global_struct->trace_allsolid = trace.allsolid;
791 pr_global_struct->trace_startsolid = trace.startsolid;
792 pr_global_struct->trace_fraction = trace.fraction;
793 pr_global_struct->trace_inwater = trace.inwater;
794 pr_global_struct->trace_inopen = trace.inopen;
795 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
796 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
797 pr_global_struct->trace_plane_dist = trace.plane.dist;
799 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
801 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
809 Returns true if the given entity can move to the given position from it's
810 current position by walking or rolling.
812 scalar checkpos (entity, vector)
815 void PF_checkpos (void)
819 //============================================================================
821 qbyte checkpvs[MAX_MAP_LEAFS/8];
823 int PF_newcheckclient (int check)
829 // cycle to the next one
831 check = bound(1, check, MAX_SCOREBOARD);
832 if (check == MAX_SCOREBOARD)
840 pr_xfunction->builtinsprofile++;
842 if (i == MAX_SCOREBOARD+1)
844 // look up the client's edict
846 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
847 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
849 // found a valid client (possibly the same one again)
853 // get the PVS for the entity
854 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
855 memcpy (checkpvs, sv.worldmodel->brushq1.LeafPVS(sv.worldmodel, sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, org)), (sv.worldmodel->brushq1.numleafs+7)>>3 );
864 Returns a client (or object that has a client enemy) that would be a
867 If there is more than one valid option, they are cycled each frame
869 If (self.origin + self.viewofs) is not in the PVS of the current target,
870 it is not returned at all.
875 int c_invis, c_notvis;
876 void PF_checkclient (void)
883 // find a new check if on a new frame
884 if (sv.time - sv.lastchecktime >= 0.1)
886 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
887 sv.lastchecktime = sv.time;
890 // return check if it might be visible
891 ent = EDICT_NUM(sv.lastcheck);
892 if (ent->e->free || ent->v->health <= 0)
894 RETURN_EDICT(sv.edicts);
898 // if current entity can't possibly see the check entity, return 0
899 self = PROG_TO_EDICT(pr_global_struct->self);
900 VectorAdd (self->v->origin, self->v->view_ofs, view);
901 leaf = sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, view);
904 l = (leaf - sv.worldmodel->brushq1.leafs) - 1;
905 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
908 RETURN_EDICT(sv.edicts);
913 // might be able to see it
918 //============================================================================
925 Sends text over to the client's execution buffer
927 stuffcmd (clientent, value)
930 void PF_stuffcmd (void)
936 entnum = G_EDICTNUM(OFS_PARM0);
937 if (entnum < 1 || entnum > MAX_SCOREBOARD)
938 Host_Error ("Parm 0 not a client");
939 str = G_STRING(OFS_PARM1);
942 if ((host_client = svs.connectedclients[entnum-1]))
943 Host_ClientCommands ("%s", str);
951 Sends text over to the client's execution buffer
956 void PF_localcmd (void)
960 str = G_STRING(OFS_PARM0);
975 str = G_STRING(OFS_PARM0);
977 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
987 void PF_cvar_set (void)
991 var = G_STRING(OFS_PARM0);
992 val = G_STRING(OFS_PARM1);
1001 Returns a chain of entities that have origins within a spherical area
1003 findradius (origin, radius)
1006 void PF_findradius (void)
1008 edict_t *ent, *chain;
1015 chain = (edict_t *)sv.edicts;
1017 org = G_VECTOR(OFS_PARM0);
1018 radius = G_FLOAT(OFS_PARM1);
1019 radius2 = radius * radius;
1021 ent = NEXT_EDICT(sv.edicts);
1022 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1024 pr_xfunction->builtinsprofile++;
1027 if (ent->v->solid == SOLID_NOT)
1030 // LordHavoc: compare against bounding box rather than center,
1031 // and use DotProduct instead of Length, major speedup
1032 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1033 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1034 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1035 if (DotProduct(eorg, eorg) > radius2)
1038 ent->v->chain = EDICT_TO_PROG(chain);
1042 RETURN_EDICT(chain);
1051 void PF_dprint (void)
1053 Con_DPrintf ("%s",PF_VarString(0));
1056 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1057 #define STRINGTEMP_BUFFERS 16
1058 #define STRINGTEMP_LENGTH 128
1059 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1060 static int pr_string_tempindex = 0;
1062 static char *PR_GetTempString(void)
1065 s = pr_string_temp[pr_string_tempindex];
1066 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1074 v = G_FLOAT(OFS_PARM0);
1076 s = PR_GetTempString();
1077 // LordHavoc: ftos improvement
1078 sprintf (s, "%g", v);
1079 G_INT(OFS_RETURN) = PR_SetString(s);
1085 v = G_FLOAT(OFS_PARM0);
1086 G_FLOAT(OFS_RETURN) = fabs(v);
1092 s = PR_GetTempString();
1093 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1094 G_INT(OFS_RETURN) = PR_SetString(s);
1100 s = PR_GetTempString();
1101 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1102 G_INT(OFS_RETURN) = PR_SetString(s);
1105 void PF_Spawn (void)
1108 pr_xfunction->builtinsprofile += 20;
1113 void PF_Remove (void)
1116 pr_xfunction->builtinsprofile += 20;
1118 ed = G_EDICT(OFS_PARM0);
1119 if (ed == sv.edicts)
1120 Host_Error("remove: tried to remove world\n");
1121 if (NUM_FOR_EDICT(ed) <= MAX_SCOREBOARD)
1122 Host_Error("remove: tried to remove a client\n");
1127 // entity (entity start, .string field, string match) find = #5;
1135 e = G_EDICTNUM(OFS_PARM0);
1136 f = G_INT(OFS_PARM1);
1137 s = G_STRING(OFS_PARM2);
1140 RETURN_EDICT(sv.edicts);
1144 for (e++ ; e < sv.num_edicts ; e++)
1146 pr_xfunction->builtinsprofile++;
1160 RETURN_EDICT(sv.edicts);
1163 // LordHavoc: added this for searching float, int, and entity reference fields
1164 void PF_FindFloat (void)
1171 e = G_EDICTNUM(OFS_PARM0);
1172 f = G_INT(OFS_PARM1);
1173 s = G_FLOAT(OFS_PARM2);
1175 for (e++ ; e < sv.num_edicts ; e++)
1177 pr_xfunction->builtinsprofile++;
1181 if (E_FLOAT(ed,f) == s)
1188 RETURN_EDICT(sv.edicts);
1191 // chained search for strings in entity fields
1192 // entity(.string field, string match) findchain = #402;
1193 void PF_findchain (void)
1198 edict_t *ent, *chain;
1200 chain = (edict_t *)sv.edicts;
1202 f = G_INT(OFS_PARM0);
1203 s = G_STRING(OFS_PARM1);
1206 RETURN_EDICT(sv.edicts);
1210 ent = NEXT_EDICT(sv.edicts);
1211 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1213 pr_xfunction->builtinsprofile++;
1216 t = E_STRING(ent,f);
1222 ent->v->chain = EDICT_TO_PROG(chain);
1226 RETURN_EDICT(chain);
1229 // LordHavoc: chained search for float, int, and entity reference fields
1230 // entity(.string field, float match) findchainfloat = #403;
1231 void PF_findchainfloat (void)
1236 edict_t *ent, *chain;
1238 chain = (edict_t *)sv.edicts;
1240 f = G_INT(OFS_PARM0);
1241 s = G_FLOAT(OFS_PARM1);
1243 ent = NEXT_EDICT(sv.edicts);
1244 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1246 pr_xfunction->builtinsprofile++;
1249 if (E_FLOAT(ent,f) != s)
1252 ent->v->chain = EDICT_TO_PROG(chain);
1256 RETURN_EDICT(chain);
1259 void PR_CheckEmptyString (char *s)
1262 Host_Error ("Bad string");
1265 void PF_precache_file (void)
1266 { // precache_file is only used to copy files with qcc, it does nothing
1267 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1270 void PF_precache_sound (void)
1275 if (sv.state != ss_loading)
1276 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1278 s = G_STRING(OFS_PARM0);
1279 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1280 PR_CheckEmptyString (s);
1282 for (i=0 ; i<MAX_SOUNDS ; i++)
1284 if (!sv.sound_precache[i])
1286 sv.sound_precache[i] = s;
1289 if (!strcmp(sv.sound_precache[i], s))
1292 Host_Error ("PF_precache_sound: overflow");
1295 void PF_precache_model (void)
1300 if (sv.state != ss_loading)
1301 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1303 s = G_STRING(OFS_PARM0);
1304 if (sv.worldmodel->brushq1.ishlbsp && ((!s) || (!s[0])))
1306 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1307 PR_CheckEmptyString (s);
1309 for (i=0 ; i<MAX_MODELS ; i++)
1311 if (!sv.model_precache[i])
1313 sv.model_precache[i] = s;
1314 sv.models[i] = Mod_ForName (s, true, false, false);
1317 if (!strcmp(sv.model_precache[i], s))
1320 Host_Error ("PF_precache_model: overflow");
1324 void PF_coredump (void)
1329 void PF_traceon (void)
1334 void PF_traceoff (void)
1339 void PF_eprint (void)
1341 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1348 float(float yaw, float dist) walkmove
1351 void PF_walkmove (void)
1359 ent = PROG_TO_EDICT(pr_global_struct->self);
1360 yaw = G_FLOAT(OFS_PARM0);
1361 dist = G_FLOAT(OFS_PARM1);
1363 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1365 G_FLOAT(OFS_RETURN) = 0;
1369 yaw = yaw*M_PI*2 / 360;
1371 move[0] = cos(yaw)*dist;
1372 move[1] = sin(yaw)*dist;
1375 // save program state, because SV_movestep may call other progs
1376 oldf = pr_xfunction;
1377 oldself = pr_global_struct->self;
1379 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1382 // restore program state
1383 pr_xfunction = oldf;
1384 pr_global_struct->self = oldself;
1394 void PF_droptofloor (void)
1400 ent = PROG_TO_EDICT(pr_global_struct->self);
1402 VectorCopy (ent->v->origin, end);
1405 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1407 if (trace.fraction == 1)
1408 G_FLOAT(OFS_RETURN) = 0;
1411 VectorCopy (trace.endpos, ent->v->origin);
1412 SV_LinkEdict (ent, false);
1413 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1414 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1415 G_FLOAT(OFS_RETURN) = 1;
1416 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1417 ent->e->suspendedinairflag = true;
1425 void(float style, string value) lightstyle
1428 void PF_lightstyle (void)
1435 style = G_FLOAT(OFS_PARM0);
1436 val = G_STRING(OFS_PARM1);
1438 // change the string in sv
1439 sv.lightstyles[style] = val;
1441 // send message to all clients on this server
1442 if (sv.state != ss_active)
1445 for (j = 0;j < MAX_SCOREBOARD;j++)
1447 if ((client = svs.connectedclients[j]))
1449 MSG_WriteChar (&client->message, svc_lightstyle);
1450 MSG_WriteChar (&client->message,style);
1451 MSG_WriteString (&client->message, val);
1459 f = G_FLOAT(OFS_PARM0);
1461 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1463 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1465 void PF_floor (void)
1467 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1471 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1480 void PF_checkbottom (void)
1482 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1490 void PF_pointcontents (void)
1492 G_FLOAT(OFS_RETURN) = SV_PointContents(G_VECTOR(OFS_PARM0));
1499 entity nextent(entity)
1502 void PF_nextent (void)
1507 i = G_EDICTNUM(OFS_PARM0);
1510 pr_xfunction->builtinsprofile++;
1512 if (i == sv.num_edicts)
1514 RETURN_EDICT(sv.edicts);
1530 Pick a vector for the player to shoot along
1531 vector aim(entity, missilespeed)
1536 edict_t *ent, *check, *bestent;
1537 vec3_t start, dir, end, bestdir;
1540 float dist, bestdist;
1543 ent = G_EDICT(OFS_PARM0);
1544 speed = G_FLOAT(OFS_PARM1);
1546 VectorCopy (ent->v->origin, start);
1549 // try sending a trace straight
1550 VectorCopy (pr_global_struct->v_forward, dir);
1551 VectorMA (start, 2048, dir, end);
1552 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1553 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1554 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1556 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1561 // try all possible entities
1562 VectorCopy (dir, bestdir);
1563 bestdist = sv_aim.value;
1566 check = NEXT_EDICT(sv.edicts);
1567 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1569 pr_xfunction->builtinsprofile++;
1570 if (check->v->takedamage != DAMAGE_AIM)
1574 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1575 continue; // don't aim at teammate
1576 for (j=0 ; j<3 ; j++)
1577 end[j] = check->v->origin[j]
1578 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1579 VectorSubtract (end, start, dir);
1580 VectorNormalize (dir);
1581 dist = DotProduct (dir, pr_global_struct->v_forward);
1582 if (dist < bestdist)
1583 continue; // to far to turn
1584 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1585 if (tr.ent == check)
1586 { // can shoot at this one
1594 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1595 dist = DotProduct (dir, pr_global_struct->v_forward);
1596 VectorScale (pr_global_struct->v_forward, dist, end);
1598 VectorNormalize (end);
1599 VectorCopy (end, G_VECTOR(OFS_RETURN));
1603 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1611 This was a major timewaster in progs, so it was converted to C
1614 void PF_changeyaw (void)
1617 float ideal, current, move, speed;
1619 ent = PROG_TO_EDICT(pr_global_struct->self);
1620 current = ANGLEMOD(ent->v->angles[1]);
1621 ideal = ent->v->ideal_yaw;
1622 speed = ent->v->yaw_speed;
1624 if (current == ideal)
1626 move = ideal - current;
1627 if (ideal > current)
1648 ent->v->angles[1] = ANGLEMOD (current + move);
1656 void PF_changepitch (void)
1659 float ideal, current, move, speed;
1662 ent = G_EDICT(OFS_PARM0);
1663 current = ANGLEMOD( ent->v->angles[0] );
1664 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1665 ideal = val->_float;
1668 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1671 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1672 speed = val->_float;
1675 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1679 if (current == ideal)
1681 move = ideal - current;
1682 if (ideal > current)
1703 ent->v->angles[0] = ANGLEMOD (current + move);
1707 ===============================================================================
1711 ===============================================================================
1714 #define MSG_BROADCAST 0 // unreliable to all
1715 #define MSG_ONE 1 // reliable to one (msg_entity)
1716 #define MSG_ALL 2 // reliable to all
1717 #define MSG_INIT 3 // write to the init string
1719 sizebuf_t *WriteDest (void)
1725 dest = G_FLOAT(OFS_PARM0);
1729 return &sv.datagram;
1732 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1733 entnum = NUM_FOR_EDICT(ent);
1734 if (entnum < 1 || entnum > MAX_SCOREBOARD || svs.connectedclients[entnum-1] == NULL)
1735 Host_Error("WriteDest: not a client");
1736 return &svs.connectedclients[entnum-1]->message;
1739 return &sv.reliable_datagram;
1745 Host_Error ("WriteDest: bad destination");
1752 void PF_WriteByte (void)
1754 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1757 void PF_WriteChar (void)
1759 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1762 void PF_WriteShort (void)
1764 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1767 void PF_WriteLong (void)
1769 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1772 void PF_WriteAngle (void)
1774 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1777 void PF_WriteCoord (void)
1779 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1782 void PF_WriteString (void)
1784 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1788 void PF_WriteEntity (void)
1790 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1793 //=============================================================================
1795 void PF_makestatic (void)
1800 ent = G_EDICT(OFS_PARM0);
1803 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1808 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1809 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1810 MSG_WriteShort (&sv.signon, ent->v->frame);
1814 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1815 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1816 MSG_WriteByte (&sv.signon, ent->v->frame);
1819 MSG_WriteByte (&sv.signon, ent->v->colormap);
1820 MSG_WriteByte (&sv.signon, ent->v->skin);
1821 for (i=0 ; i<3 ; i++)
1823 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1824 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1827 // throw the entity away now
1831 //=============================================================================
1838 void PF_setspawnparms (void)
1844 ent = G_EDICT(OFS_PARM0);
1845 i = NUM_FOR_EDICT(ent);
1846 if (i < 1 || i > MAX_SCOREBOARD || !svs.connectedclients[i-1])
1847 Host_Error ("Entity is not a client");
1849 // copy spawn parms out of the client_t
1850 client = svs.connectedclients[i-1];
1851 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1852 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1860 void PF_changelevel (void)
1864 // make sure we don't issue two changelevels
1865 if (svs.changelevel_issued)
1867 svs.changelevel_issued = true;
1869 s = G_STRING(OFS_PARM0);
1870 Cbuf_AddText (va("changelevel %s\n",s));
1875 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1880 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1885 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1892 Returns a vector of length < 1
1897 void PF_randomvec (void)
1902 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1903 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1904 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1906 while (DotProduct(temp, temp) >= 1);
1907 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1914 Returns a color vector indicating the lighting at the requested point.
1916 (Internal Operation note: actually measures the light beneath the point, just like
1917 the model lighting on the client)
1922 void PF_GetLight (void)
1924 vec3_t ambientcolor, diffusecolor, diffusenormal;
1926 p = G_VECTOR(OFS_PARM0);
1927 VectorClear(ambientcolor);
1928 VectorClear(diffusecolor);
1929 VectorClear(diffusenormal);
1930 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1931 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1932 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1935 #define MAX_QC_CVARS 128
1936 cvar_t qc_cvar[MAX_QC_CVARS];
1939 void PF_registercvar (void)
1943 name = G_STRING(OFS_PARM0);
1944 value = G_STRING(OFS_PARM1);
1945 G_FLOAT(OFS_RETURN) = 0;
1946 // first check to see if it has already been defined
1947 if (Cvar_FindVar (name))
1950 // check for overlap with a command
1951 if (Cmd_Exists (name))
1953 Con_Printf ("PF_registercvar: %s is a command\n", name);
1957 if (currentqc_cvar >= MAX_QC_CVARS)
1958 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1960 // copy the name and value
1961 variable = &qc_cvar[currentqc_cvar++];
1962 variable->name = Z_Malloc (strlen(name)+1);
1963 strcpy (variable->name, name);
1964 variable->string = Z_Malloc (strlen(value)+1);
1965 strcpy (variable->string, value);
1966 variable->value = atof (value);
1968 Cvar_RegisterVariable(variable);
1969 G_FLOAT(OFS_RETURN) = 1; // success
1976 returns the minimum of two supplied floats
1983 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1985 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1986 else if (pr_argc >= 3)
1989 float f = G_FLOAT(OFS_PARM0);
1990 for (i = 1;i < pr_argc;i++)
1991 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1992 f = G_FLOAT((OFS_PARM0+i*3));
1993 G_FLOAT(OFS_RETURN) = f;
1996 Host_Error("min: must supply at least 2 floats\n");
2003 returns the maximum of two supplied floats
2010 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2012 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2013 else if (pr_argc >= 3)
2016 float f = G_FLOAT(OFS_PARM0);
2017 for (i = 1;i < pr_argc;i++)
2018 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2019 f = G_FLOAT((OFS_PARM0+i*3));
2020 G_FLOAT(OFS_RETURN) = f;
2023 Host_Error("max: must supply at least 2 floats\n");
2030 returns number bounded by supplied range
2032 min(min, value, max)
2035 void PF_bound (void)
2037 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2044 returns a raised to power b
2051 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2058 copies data from one entity to another
2060 copyentity(src, dst)
2063 void PF_copyentity (void)
2066 in = G_EDICT(OFS_PARM0);
2067 out = G_EDICT(OFS_PARM1);
2068 memcpy(out->v, in->v, progs->entityfields * 4);
2075 sets the color of a client and broadcasts the update to all connected clients
2077 setcolor(clientent, value)
2080 void PF_setcolor (void)
2086 entnum = G_EDICTNUM(OFS_PARM0);
2087 i = G_FLOAT(OFS_PARM1);
2089 if (entnum < 1 || entnum > MAX_SCOREBOARD || !(client = svs.connectedclients[entnum-1]))
2091 Con_Printf ("tried to setcolor a non-client\n");
2095 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2098 client->old_colors = i;
2099 client->edict->v->team = (i & 15) + 1;
2101 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2102 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2103 MSG_WriteByte (&sv.reliable_datagram, i);
2110 effect(origin, modelname, startframe, framecount, framerate)
2113 void PF_effect (void)
2116 s = G_STRING(OFS_PARM1);
2118 Host_Error("effect: no model specified\n");
2120 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2123 void PF_te_blood (void)
2125 if (G_FLOAT(OFS_PARM2) < 1)
2127 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2128 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2130 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2131 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2132 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2134 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2135 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2136 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2138 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2141 void PF_te_bloodshower (void)
2143 if (G_FLOAT(OFS_PARM3) < 1)
2145 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2146 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2148 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2149 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2150 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2152 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2153 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2154 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2156 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2158 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2161 void PF_te_explosionrgb (void)
2163 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2164 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2166 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2167 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2168 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2170 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2171 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2172 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2175 void PF_te_particlecube (void)
2177 if (G_FLOAT(OFS_PARM3) < 1)
2179 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2180 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2184 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2186 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2190 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2191 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2192 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2194 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2196 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2197 // gravity true/false
2198 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2200 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2203 void PF_te_particlerain (void)
2205 if (G_FLOAT(OFS_PARM3) < 1)
2207 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2208 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2218 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2219 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2220 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2222 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2224 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2227 void PF_te_particlesnow (void)
2229 if (G_FLOAT(OFS_PARM3) < 1)
2231 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2232 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2242 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2243 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2244 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2246 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2248 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2251 void PF_te_spark (void)
2253 if (G_FLOAT(OFS_PARM2) < 1)
2255 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2256 MSG_WriteByte(&sv.datagram, TE_SPARK);
2258 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2259 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2260 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2262 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2263 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2264 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2266 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2269 void PF_te_gunshotquad (void)
2271 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2272 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2274 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2275 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2276 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2279 void PF_te_spikequad (void)
2281 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2282 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2286 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2289 void PF_te_superspikequad (void)
2291 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2292 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2294 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2295 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2296 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2299 void PF_te_explosionquad (void)
2301 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2302 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2306 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2309 void PF_te_smallflash (void)
2311 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2312 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2314 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2315 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2316 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2319 void PF_te_customflash (void)
2321 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2323 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2324 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2326 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2327 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2328 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2330 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2332 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2334 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2335 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2336 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2339 void PF_te_gunshot (void)
2341 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2342 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2344 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2345 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2346 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2349 void PF_te_spike (void)
2351 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2352 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2354 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2355 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2356 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2359 void PF_te_superspike (void)
2361 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2362 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2364 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2365 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2366 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2369 void PF_te_explosion (void)
2371 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2372 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2375 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2376 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2379 void PF_te_tarexplosion (void)
2381 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2382 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2384 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2385 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2386 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2389 void PF_te_wizspike (void)
2391 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2394 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2395 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2396 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2399 void PF_te_knightspike (void)
2401 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2402 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2404 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2405 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2406 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2409 void PF_te_lavasplash (void)
2411 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2412 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2414 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2415 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2416 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2419 void PF_te_teleport (void)
2421 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2424 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2425 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2426 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2429 void PF_te_explosion2 (void)
2431 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2432 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2434 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2435 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2436 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2438 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2441 void PF_te_lightning1 (void)
2443 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2444 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2446 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2448 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2452 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2453 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2454 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2457 void PF_te_lightning2 (void)
2459 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2462 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2465 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2466 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2468 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2469 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2470 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2473 void PF_te_lightning3 (void)
2475 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2476 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2478 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2484 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2485 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2486 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2489 void PF_te_beam (void)
2491 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2492 MSG_WriteByte(&sv.datagram, TE_BEAM);
2494 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2501 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2502 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2505 void PF_te_plasmaburn (void)
2507 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2508 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2509 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2510 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2511 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2514 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2517 vec3_t v1, clipplanenormal, normal;
2518 vec_t clipplanedist, clipdist;
2520 if (surf->flags & SURF_PLANEBACK)
2521 VectorNegate(surf->plane->normal, normal);
2523 VectorCopy(surf->plane->normal, normal);
2524 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2526 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2527 VectorNormalizeFast(v1);
2528 CrossProduct(v1, normal, clipplanenormal);
2529 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2530 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2533 clipdist = -clipdist;
2534 VectorMA(out, clipdist, clipplanenormal, out);
2539 static msurface_t *getsurface(edict_t *ed, int surfnum)
2543 if (!ed || ed->e->free)
2545 modelindex = ed->v->modelindex;
2546 if (modelindex < 1 || modelindex >= MAX_MODELS)
2548 model = sv.models[modelindex];
2549 if (model->type != mod_brush)
2551 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2553 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2557 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2558 void PF_getsurfacenumpoints(void)
2561 // return 0 if no such surface
2562 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2564 G_FLOAT(OFS_RETURN) = 0;
2568 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2570 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2571 void PF_getsurfacepoint(void)
2576 VectorClear(G_VECTOR(OFS_RETURN));
2577 ed = G_EDICT(OFS_PARM0);
2578 if (!ed || ed->e->free)
2580 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2582 pointnum = G_FLOAT(OFS_PARM2);
2583 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2585 // FIXME: implement rotation/scaling
2586 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2588 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2589 void PF_getsurfacenormal(void)
2592 VectorClear(G_VECTOR(OFS_RETURN));
2593 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2595 // FIXME: implement rotation/scaling
2596 if (surf->flags & SURF_PLANEBACK)
2597 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2599 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2601 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2602 void PF_getsurfacetexture(void)
2605 G_INT(OFS_RETURN) = 0;
2606 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2608 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2610 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2611 void PF_getsurfacenearpoint(void)
2613 int surfnum, best, modelindex;
2615 vec_t dist, bestdist;
2620 G_FLOAT(OFS_RETURN) = -1;
2621 ed = G_EDICT(OFS_PARM0);
2622 point = G_VECTOR(OFS_PARM1);
2624 if (!ed || ed->e->free)
2626 modelindex = ed->v->modelindex;
2627 if (modelindex < 1 || modelindex >= MAX_MODELS)
2629 model = sv.models[modelindex];
2630 if (model->type != mod_brush)
2633 // FIXME: implement rotation/scaling
2634 VectorSubtract(point, ed->v->origin, p);
2636 bestdist = 1000000000;
2637 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2639 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2640 dist = PlaneDiff(p, surf->plane);
2642 if (dist < bestdist)
2644 clippointtosurface(surf, p, clipped);
2645 VectorSubtract(clipped, p, clipped);
2646 dist += DotProduct(clipped, clipped);
2647 if (dist < bestdist)
2654 G_FLOAT(OFS_RETURN) = best;
2656 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2657 void PF_getsurfaceclippedpoint(void)
2662 VectorClear(G_VECTOR(OFS_RETURN));
2663 ed = G_EDICT(OFS_PARM0);
2664 if (!ed || ed->e->free)
2666 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2668 // FIXME: implement rotation/scaling
2669 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2670 clippointtosurface(surf, p, out);
2671 // FIXME: implement rotation/scaling
2672 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2675 #define MAX_PRFILES 256
2677 qfile_t *pr_files[MAX_PRFILES];
2679 void PR_Files_Init(void)
2681 memset(pr_files, 0, sizeof(pr_files));
2684 void PR_Files_CloseAll(void)
2687 for (i = 0;i < MAX_PRFILES;i++)
2690 FS_Close(pr_files[i]);
2695 //float(string s) stof = #81; // get numerical value from a string
2698 char *s = PF_VarString(0);
2699 G_FLOAT(OFS_RETURN) = atof(s);
2702 //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
2706 char *modestring, *filename;
2707 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2708 if (pr_files[filenum] == NULL)
2710 if (filenum >= MAX_PRFILES)
2712 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2713 G_FLOAT(OFS_RETURN) = -2;
2716 mode = G_FLOAT(OFS_PARM1);
2719 case 0: // FILE_READ
2722 case 1: // FILE_APPEND
2725 case 2: // FILE_WRITE
2729 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2730 G_FLOAT(OFS_RETURN) = -3;
2733 filename = G_STRING(OFS_PARM0);
2734 // .. is parent directory on many platforms
2735 // / is parent directory on Amiga
2736 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2737 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2738 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2740 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2741 G_FLOAT(OFS_RETURN) = -4;
2744 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2745 if (pr_files[filenum] == NULL)
2746 G_FLOAT(OFS_RETURN) = -1;
2748 G_FLOAT(OFS_RETURN) = filenum;
2751 //void(float fhandle) fclose = #111; // closes a file
2752 void PF_fclose(void)
2754 int filenum = G_FLOAT(OFS_PARM0);
2755 if (filenum < 0 || filenum >= MAX_PRFILES)
2757 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2760 if (pr_files[filenum] == NULL)
2762 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2765 FS_Close(pr_files[filenum]);
2766 pr_files[filenum] = NULL;
2769 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2773 static char string[MAX_VARSTRING];
2774 int filenum = G_FLOAT(OFS_PARM0);
2775 if (filenum < 0 || filenum >= MAX_PRFILES)
2777 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2780 if (pr_files[filenum] == NULL)
2782 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2788 c = FS_Getc(pr_files[filenum]);
2789 if (c == '\r' || c == '\n' || c < 0)
2791 if (end < MAX_VARSTRING - 1)
2795 // remove \n following \r
2797 c = FS_Getc(pr_files[filenum]);
2798 if (developer.integer)
2799 Con_Printf("fgets: %s\n", string);
2801 G_INT(OFS_RETURN) = PR_SetString(string);
2803 G_INT(OFS_RETURN) = 0;
2806 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2810 char *s = PF_VarString(1);
2811 int filenum = G_FLOAT(OFS_PARM0);
2812 if (filenum < 0 || filenum >= MAX_PRFILES)
2814 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2817 if (pr_files[filenum] == NULL)
2819 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2822 if ((stringlength = strlen(s)))
2823 FS_Write(pr_files[filenum], s, stringlength);
2824 if (developer.integer)
2825 Con_Printf("fputs: %s\n", s);
2828 //float(string s) strlen = #114; // returns how many characters are in a string
2829 void PF_strlen(void)
2832 s = G_STRING(OFS_PARM0);
2834 G_FLOAT(OFS_RETURN) = strlen(s);
2836 G_FLOAT(OFS_RETURN) = 0;
2839 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2840 void PF_strcat(void)
2842 char *s = PF_VarString(0);
2843 G_INT(OFS_RETURN) = PR_SetString(s);
2846 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2847 void PF_substring(void)
2849 int i, start, length;
2850 char *s, *string = PR_GetTempString();
2851 s = G_STRING(OFS_PARM0);
2852 start = G_FLOAT(OFS_PARM1);
2853 length = G_FLOAT(OFS_PARM2);
2856 for (i = 0;i < start && *s;i++, s++);
2857 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2860 G_INT(OFS_RETURN) = PR_SetString(string);
2863 //vector(string s) stov = #117; // returns vector value from a string
2866 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2869 //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)
2870 void PF_strzone(void)
2873 in = G_STRING(OFS_PARM0);
2874 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2876 G_INT(OFS_RETURN) = PR_SetString(out);
2879 //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!!!)
2880 void PF_strunzone(void)
2882 Mem_Free(G_STRING(OFS_PARM0));
2885 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2886 //this function originally written by KrimZon, made shorter by LordHavoc
2887 void PF_clientcommand (void)
2889 client_t *temp_client;
2892 //find client for this entity
2893 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2894 if (i < 0 || i >= MAX_SCOREBOARD || !svs.connectedclients[i])
2895 Host_Error("PF_clientcommand: entity is not a client");
2897 temp_client = host_client;
2898 host_client = svs.connectedclients[i];
2899 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2900 host_client = temp_client;
2903 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2904 //this function originally written by KrimZon, made shorter by LordHavoc
2905 char **tokens = NULL;
2906 int max_tokens, num_tokens = 0;
2907 void PF_tokenize (void)
2911 str = G_STRING(OFS_PARM0);
2916 for (i=0;i<num_tokens;i++)
2922 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2923 max_tokens = strlen(str);
2925 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2927 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2928 strcpy(tokens[num_tokens], com_token);
2931 G_FLOAT(OFS_RETURN) = num_tokens;
2934 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2935 //this function originally written by KrimZon, made shorter by LordHavoc
2938 int token_num = G_FLOAT(OFS_PARM0);
2939 if (token_num >= 0 && token_num < num_tokens)
2940 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2942 G_INT(OFS_RETURN) = PR_SetString("");
2945 //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)
2946 void PF_setattachment (void)
2948 edict_t *e = G_EDICT(OFS_PARM0);
2949 edict_t *tagentity = G_EDICT(OFS_PARM1);
2950 char *tagname = G_STRING(OFS_PARM2);
2955 if (tagentity == NULL)
2956 tagentity = sv.edicts;
2958 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2960 v->edict = EDICT_TO_PROG(tagentity);
2962 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2965 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2967 modelindex = (int)tagentity->v->modelindex;
2968 if (modelindex >= 0 && modelindex < MAX_MODELS)
2970 model = sv.models[modelindex];
2971 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2972 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2973 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2975 if (v->_float == 0 && model->alias.aliasnum_tags)
2976 for (i = 0;i < model->alias.aliasnum_tags;i++)
2977 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2980 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);
2983 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));
2988 builtin_t pr_builtin[] =
2991 PF_makevectors, // #1 void(entity e) makevectors
2992 PF_setorigin, // #2 void(entity e, vector o) setorigin
2993 PF_setmodel, // #3 void(entity e, string m) setmodel
2994 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2995 NULL, // #5 void(entity e, vector min, vector max) setabssize
2996 PF_break, // #6 void() break
2997 PF_random, // #7 float() random
2998 PF_sound, // #8 void(entity e, float chan, string samp) sound
2999 PF_normalize, // #9 vector(vector v) normalize
3000 PF_error, // #10 void(string e) error
3001 PF_objerror, // #11 void(string e) objerror
3002 PF_vlen, // #12 float(vector v) vlen
3003 PF_vectoyaw, // #13 float(vector v) vectoyaw
3004 PF_Spawn, // #14 entity() spawn
3005 PF_Remove, // #15 void(entity e) remove
3006 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3007 PF_checkclient, // #17 entity() clientlist
3008 PF_Find, // #18 entity(entity start, .string fld, string match) find
3009 PF_precache_sound, // #19 void(string s) precache_sound
3010 PF_precache_model, // #20 void(string s) precache_model
3011 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3012 PF_findradius, // #22 entity(vector org, float rad) findradius
3013 PF_bprint, // #23 void(string s) bprint
3014 PF_sprint, // #24 void(entity client, string s) sprint
3015 PF_dprint, // #25 void(string s) dprint
3016 PF_ftos, // #26 void(string s) ftos
3017 PF_vtos, // #27 void(string s) vtos
3018 PF_coredump, // #28 void() coredump
3019 PF_traceon, // #29 void() traceon
3020 PF_traceoff, // #30 void() traceoff
3021 PF_eprint, // #31 void(entity e) eprint
3022 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3024 PF_droptofloor, // #34 float() droptofloor
3025 PF_lightstyle, // #35 void(float style, string value) lightstyle
3026 PF_rint, // #36 float(float v) rint
3027 PF_floor, // #37 float(float v) floor
3028 PF_ceil, // #38 float(float v) ceil
3030 PF_checkbottom, // #40 float(entity e) checkbottom
3031 PF_pointcontents , // #41 float(vector v) pointcontents
3033 PF_fabs, // #43 float(float f) fabs
3034 PF_aim, // #44 vector(entity e, float speed) aim
3035 PF_cvar, // #45 float(string s) cvar
3036 PF_localcmd, // #46 void(string s) localcmd
3037 PF_nextent, // #47 entity(entity e) nextent
3038 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3039 PF_changeyaw, // #49 void() ChangeYaw
3041 PF_vectoangles, // #51 vector(vector v) vectoangles
3042 PF_WriteByte, // #52 void(float to, float f) WriteByte
3043 PF_WriteChar, // #53 void(float to, float f) WriteChar
3044 PF_WriteShort, // #54 void(float to, float f) WriteShort
3045 PF_WriteLong, // #55 void(float to, float f) WriteLong
3046 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3047 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3048 PF_WriteString, // #58 void(float to, string s) WriteString
3049 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3050 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3051 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3052 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3053 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3054 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3055 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3057 SV_MoveToGoal, // #67 void(float step) movetogoal
3058 PF_precache_file, // #68 string(string s) precache_file
3059 PF_makestatic, // #69 void(entity e) makestatic
3060 PF_changelevel, // #70 void(string s) changelevel
3062 PF_cvar_set, // #72 void(string var, string val) cvar_set
3063 PF_centerprint, // #73 void(entity client, strings) centerprint
3064 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3065 PF_precache_model, // #75 string(string s) precache_model2
3066 PF_precache_sound, // #76 string(string s) precache_sound2
3067 PF_precache_file, // #77 string(string s) precache_file2
3068 PF_setspawnparms, // #78 void(entity e) setspawnparms
3071 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3080 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3081 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3082 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3083 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3084 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3085 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3086 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3087 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3088 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3089 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3100 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3101 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3102 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3103 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3104 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3105 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3106 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3107 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3108 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3109 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3110 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3111 a a a a a a a a // #120-199
3112 a a a a a a a a a a // #200-299
3113 a a a a a a a a a a // #300-399
3114 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3115 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3116 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3117 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3118 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3119 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3120 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3121 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3122 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3123 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3124 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3125 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3126 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3127 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3128 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3129 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3130 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3131 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3132 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3133 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3134 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3135 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3136 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3137 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3138 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3139 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3140 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3141 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3142 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3143 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3144 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3145 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3146 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3147 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3148 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3149 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3150 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3151 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3152 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3153 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3154 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3155 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3156 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3157 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3164 a a a a a // #450-499 (LordHavoc)
3167 builtin_t *pr_builtins = pr_builtin;
3168 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3170 void PR_Cmd_Init(void)
3172 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3176 void PR_Cmd_Reset(void)
3178 Mem_EmptyPool(pr_strings_mempool);
3179 PR_Files_CloseAll();