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 //============================================================================
822 qbyte checkpvs[MAX_MAP_LEAFS/8];
824 int PF_newcheckclient (int check)
830 // cycle to the next one
832 check = bound(1, check, MAX_SCOREBOARD);
833 if (check == MAX_SCOREBOARD)
841 pr_xfunction->builtinsprofile++;
843 if (i == MAX_SCOREBOARD+1)
845 // look up the client's edict
847 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
848 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
850 // found a valid client (possibly the same one again)
854 // get the PVS for the entity
855 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
857 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
858 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
867 Returns a client (or object that has a client enemy) that would be a
870 If there is more than one valid option, they are cycled each frame
872 If (self.origin + self.viewofs) is not in the PVS of the current target,
873 it is not returned at all.
878 int c_invis, c_notvis;
879 void PF_checkclient (void)
884 // find a new check if on a new frame
885 if (sv.time - sv.lastchecktime >= 0.1)
887 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
888 sv.lastchecktime = sv.time;
891 // return check if it might be visible
892 ent = EDICT_NUM(sv.lastcheck);
893 if (ent->e->free || ent->v->health <= 0)
895 RETURN_EDICT(sv.edicts);
899 // if current entity can't possibly see the check entity, return 0
900 self = PROG_TO_EDICT(pr_global_struct->self);
901 VectorAdd(self->v->origin, self->v->view_ofs, view);
902 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
905 RETURN_EDICT(sv.edicts);
909 // might be able to see it
914 //============================================================================
921 Sends text over to the client's execution buffer
923 stuffcmd (clientent, value)
926 void PF_stuffcmd (void)
932 entnum = G_EDICTNUM(OFS_PARM0);
933 if (entnum < 1 || entnum > MAX_SCOREBOARD)
934 Host_Error ("Parm 0 not a client");
935 str = G_STRING(OFS_PARM1);
938 if ((host_client = svs.connectedclients[entnum-1]))
939 Host_ClientCommands ("%s", str);
947 Sends text over to the client's execution buffer
952 void PF_localcmd (void)
956 str = G_STRING(OFS_PARM0);
971 str = G_STRING(OFS_PARM0);
973 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
983 void PF_cvar_set (void)
987 var = G_STRING(OFS_PARM0);
988 val = G_STRING(OFS_PARM1);
997 Returns a chain of entities that have origins within a spherical area
999 findradius (origin, radius)
1002 void PF_findradius (void)
1004 edict_t *ent, *chain;
1011 chain = (edict_t *)sv.edicts;
1013 org = G_VECTOR(OFS_PARM0);
1014 radius = G_FLOAT(OFS_PARM1);
1015 radius2 = radius * radius;
1017 ent = NEXT_EDICT(sv.edicts);
1018 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1020 pr_xfunction->builtinsprofile++;
1023 if (ent->v->solid == SOLID_NOT)
1026 // LordHavoc: compare against bounding box rather than center,
1027 // and use DotProduct instead of Length, major speedup
1028 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1029 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1030 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1031 if (DotProduct(eorg, eorg) > radius2)
1034 ent->v->chain = EDICT_TO_PROG(chain);
1038 RETURN_EDICT(chain);
1047 void PF_dprint (void)
1049 Con_DPrintf ("%s",PF_VarString(0));
1052 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1053 #define STRINGTEMP_BUFFERS 16
1054 #define STRINGTEMP_LENGTH 128
1055 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1056 static int pr_string_tempindex = 0;
1058 static char *PR_GetTempString(void)
1061 s = pr_string_temp[pr_string_tempindex];
1062 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1070 v = G_FLOAT(OFS_PARM0);
1072 s = PR_GetTempString();
1073 if ((float)((int)v) == v)
1074 sprintf(s, "%i", (int)v);
1076 sprintf(s, "%f", v);
1077 G_INT(OFS_RETURN) = PR_SetString(s);
1083 v = G_FLOAT(OFS_PARM0);
1084 G_FLOAT(OFS_RETURN) = fabs(v);
1090 s = PR_GetTempString();
1091 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1092 G_INT(OFS_RETURN) = PR_SetString(s);
1098 s = PR_GetTempString();
1099 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1100 G_INT(OFS_RETURN) = PR_SetString(s);
1103 void PF_Spawn (void)
1106 pr_xfunction->builtinsprofile += 20;
1111 void PF_Remove (void)
1114 pr_xfunction->builtinsprofile += 20;
1116 ed = G_EDICT(OFS_PARM0);
1117 if (ed == sv.edicts)
1118 Host_Error("remove: tried to remove world\n");
1119 if (NUM_FOR_EDICT(ed) <= MAX_SCOREBOARD)
1120 Host_Error("remove: tried to remove a client\n");
1125 // entity (entity start, .string field, string match) find = #5;
1133 e = G_EDICTNUM(OFS_PARM0);
1134 f = G_INT(OFS_PARM1);
1135 s = G_STRING(OFS_PARM2);
1138 RETURN_EDICT(sv.edicts);
1142 for (e++ ; e < sv.num_edicts ; e++)
1144 pr_xfunction->builtinsprofile++;
1158 RETURN_EDICT(sv.edicts);
1161 // LordHavoc: added this for searching float, int, and entity reference fields
1162 void PF_FindFloat (void)
1169 e = G_EDICTNUM(OFS_PARM0);
1170 f = G_INT(OFS_PARM1);
1171 s = G_FLOAT(OFS_PARM2);
1173 for (e++ ; e < sv.num_edicts ; e++)
1175 pr_xfunction->builtinsprofile++;
1179 if (E_FLOAT(ed,f) == s)
1186 RETURN_EDICT(sv.edicts);
1189 // chained search for strings in entity fields
1190 // entity(.string field, string match) findchain = #402;
1191 void PF_findchain (void)
1196 edict_t *ent, *chain;
1198 chain = (edict_t *)sv.edicts;
1200 f = G_INT(OFS_PARM0);
1201 s = G_STRING(OFS_PARM1);
1204 RETURN_EDICT(sv.edicts);
1208 ent = NEXT_EDICT(sv.edicts);
1209 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1211 pr_xfunction->builtinsprofile++;
1214 t = E_STRING(ent,f);
1220 ent->v->chain = EDICT_TO_PROG(chain);
1224 RETURN_EDICT(chain);
1227 // LordHavoc: chained search for float, int, and entity reference fields
1228 // entity(.string field, float match) findchainfloat = #403;
1229 void PF_findchainfloat (void)
1234 edict_t *ent, *chain;
1236 chain = (edict_t *)sv.edicts;
1238 f = G_INT(OFS_PARM0);
1239 s = G_FLOAT(OFS_PARM1);
1241 ent = NEXT_EDICT(sv.edicts);
1242 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1244 pr_xfunction->builtinsprofile++;
1247 if (E_FLOAT(ent,f) != s)
1250 ent->v->chain = EDICT_TO_PROG(chain);
1254 RETURN_EDICT(chain);
1257 void PR_CheckEmptyString (char *s)
1260 Host_Error ("Bad string");
1263 void PF_precache_file (void)
1264 { // precache_file is only used to copy files with qcc, it does nothing
1265 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1268 void PF_precache_sound (void)
1273 if (sv.state != ss_loading)
1274 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1276 s = G_STRING(OFS_PARM0);
1277 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1278 PR_CheckEmptyString (s);
1280 for (i=0 ; i<MAX_SOUNDS ; i++)
1282 if (!sv.sound_precache[i])
1284 sv.sound_precache[i] = s;
1287 if (!strcmp(sv.sound_precache[i], s))
1290 Host_Error ("PF_precache_sound: overflow");
1293 void PF_precache_model (void)
1298 if (sv.state != ss_loading)
1299 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1301 s = G_STRING(OFS_PARM0);
1302 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1304 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1305 PR_CheckEmptyString (s);
1307 for (i=0 ; i<MAX_MODELS ; i++)
1309 if (!sv.model_precache[i])
1311 sv.model_precache[i] = s;
1312 sv.models[i] = Mod_ForName (s, true, false, false);
1315 if (!strcmp(sv.model_precache[i], s))
1318 Host_Error ("PF_precache_model: overflow");
1322 void PF_coredump (void)
1327 void PF_traceon (void)
1332 void PF_traceoff (void)
1337 void PF_eprint (void)
1339 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1346 float(float yaw, float dist) walkmove
1349 void PF_walkmove (void)
1357 ent = PROG_TO_EDICT(pr_global_struct->self);
1358 yaw = G_FLOAT(OFS_PARM0);
1359 dist = G_FLOAT(OFS_PARM1);
1361 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1363 G_FLOAT(OFS_RETURN) = 0;
1367 yaw = yaw*M_PI*2 / 360;
1369 move[0] = cos(yaw)*dist;
1370 move[1] = sin(yaw)*dist;
1373 // save program state, because SV_movestep may call other progs
1374 oldf = pr_xfunction;
1375 oldself = pr_global_struct->self;
1377 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1380 // restore program state
1381 pr_xfunction = oldf;
1382 pr_global_struct->self = oldself;
1392 void PF_droptofloor (void)
1398 ent = PROG_TO_EDICT(pr_global_struct->self);
1400 VectorCopy (ent->v->origin, end);
1403 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1405 if (trace.fraction == 1)
1406 G_FLOAT(OFS_RETURN) = 0;
1409 VectorCopy (trace.endpos, ent->v->origin);
1410 SV_LinkEdict (ent, false);
1411 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1412 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1413 G_FLOAT(OFS_RETURN) = 1;
1414 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1415 ent->e->suspendedinairflag = true;
1423 void(float style, string value) lightstyle
1426 void PF_lightstyle (void)
1433 style = G_FLOAT(OFS_PARM0);
1434 val = G_STRING(OFS_PARM1);
1436 // change the string in sv
1437 sv.lightstyles[style] = val;
1439 // send message to all clients on this server
1440 if (sv.state != ss_active)
1443 for (j = 0;j < MAX_SCOREBOARD;j++)
1445 if ((client = svs.connectedclients[j]))
1447 MSG_WriteChar (&client->message, svc_lightstyle);
1448 MSG_WriteChar (&client->message,style);
1449 MSG_WriteString (&client->message, val);
1457 f = G_FLOAT(OFS_PARM0);
1459 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1461 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1463 void PF_floor (void)
1465 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1469 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1478 void PF_checkbottom (void)
1480 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1488 void PF_pointcontents (void)
1490 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1497 entity nextent(entity)
1500 void PF_nextent (void)
1505 i = G_EDICTNUM(OFS_PARM0);
1508 pr_xfunction->builtinsprofile++;
1510 if (i == sv.num_edicts)
1512 RETURN_EDICT(sv.edicts);
1528 Pick a vector for the player to shoot along
1529 vector aim(entity, missilespeed)
1534 edict_t *ent, *check, *bestent;
1535 vec3_t start, dir, end, bestdir;
1538 float dist, bestdist;
1541 ent = G_EDICT(OFS_PARM0);
1542 speed = G_FLOAT(OFS_PARM1);
1544 VectorCopy (ent->v->origin, start);
1547 // try sending a trace straight
1548 VectorCopy (pr_global_struct->v_forward, dir);
1549 VectorMA (start, 2048, dir, end);
1550 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1551 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1552 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1554 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1559 // try all possible entities
1560 VectorCopy (dir, bestdir);
1561 bestdist = sv_aim.value;
1564 check = NEXT_EDICT(sv.edicts);
1565 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1567 pr_xfunction->builtinsprofile++;
1568 if (check->v->takedamage != DAMAGE_AIM)
1572 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1573 continue; // don't aim at teammate
1574 for (j=0 ; j<3 ; j++)
1575 end[j] = check->v->origin[j]
1576 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1577 VectorSubtract (end, start, dir);
1578 VectorNormalize (dir);
1579 dist = DotProduct (dir, pr_global_struct->v_forward);
1580 if (dist < bestdist)
1581 continue; // to far to turn
1582 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1583 if (tr.ent == check)
1584 { // can shoot at this one
1592 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1593 dist = DotProduct (dir, pr_global_struct->v_forward);
1594 VectorScale (pr_global_struct->v_forward, dist, end);
1596 VectorNormalize (end);
1597 VectorCopy (end, G_VECTOR(OFS_RETURN));
1601 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1609 This was a major timewaster in progs, so it was converted to C
1612 void PF_changeyaw (void)
1615 float ideal, current, move, speed;
1617 ent = PROG_TO_EDICT(pr_global_struct->self);
1618 current = ANGLEMOD(ent->v->angles[1]);
1619 ideal = ent->v->ideal_yaw;
1620 speed = ent->v->yaw_speed;
1622 if (current == ideal)
1624 move = ideal - current;
1625 if (ideal > current)
1646 ent->v->angles[1] = ANGLEMOD (current + move);
1654 void PF_changepitch (void)
1657 float ideal, current, move, speed;
1660 ent = G_EDICT(OFS_PARM0);
1661 current = ANGLEMOD( ent->v->angles[0] );
1662 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1663 ideal = val->_float;
1666 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1669 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1670 speed = val->_float;
1673 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1677 if (current == ideal)
1679 move = ideal - current;
1680 if (ideal > current)
1701 ent->v->angles[0] = ANGLEMOD (current + move);
1705 ===============================================================================
1709 ===============================================================================
1712 #define MSG_BROADCAST 0 // unreliable to all
1713 #define MSG_ONE 1 // reliable to one (msg_entity)
1714 #define MSG_ALL 2 // reliable to all
1715 #define MSG_INIT 3 // write to the init string
1717 sizebuf_t *WriteDest (void)
1723 dest = G_FLOAT(OFS_PARM0);
1727 return &sv.datagram;
1730 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1731 entnum = NUM_FOR_EDICT(ent);
1732 if (entnum < 1 || entnum > MAX_SCOREBOARD || svs.connectedclients[entnum-1] == NULL)
1733 Host_Error("WriteDest: not a client");
1734 return &svs.connectedclients[entnum-1]->message;
1737 return &sv.reliable_datagram;
1743 Host_Error ("WriteDest: bad destination");
1750 void PF_WriteByte (void)
1752 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1755 void PF_WriteChar (void)
1757 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1760 void PF_WriteShort (void)
1762 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1765 void PF_WriteLong (void)
1767 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1770 void PF_WriteAngle (void)
1772 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1775 void PF_WriteCoord (void)
1777 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1780 void PF_WriteString (void)
1782 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1786 void PF_WriteEntity (void)
1788 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1791 //=============================================================================
1793 void PF_makestatic (void)
1798 ent = G_EDICT(OFS_PARM0);
1801 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1806 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1807 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1808 MSG_WriteShort (&sv.signon, ent->v->frame);
1812 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1813 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1814 MSG_WriteByte (&sv.signon, ent->v->frame);
1817 MSG_WriteByte (&sv.signon, ent->v->colormap);
1818 MSG_WriteByte (&sv.signon, ent->v->skin);
1819 for (i=0 ; i<3 ; i++)
1821 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1822 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1825 // throw the entity away now
1829 //=============================================================================
1836 void PF_setspawnparms (void)
1842 ent = G_EDICT(OFS_PARM0);
1843 i = NUM_FOR_EDICT(ent);
1844 if (i < 1 || i > MAX_SCOREBOARD || !svs.connectedclients[i-1])
1845 Host_Error ("Entity is not a client");
1847 // copy spawn parms out of the client_t
1848 client = svs.connectedclients[i-1];
1849 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1850 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1858 void PF_changelevel (void)
1862 // make sure we don't issue two changelevels
1863 if (svs.changelevel_issued)
1865 svs.changelevel_issued = true;
1867 s = G_STRING(OFS_PARM0);
1868 Cbuf_AddText (va("changelevel %s\n",s));
1873 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1878 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1883 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1890 Returns a vector of length < 1
1895 void PF_randomvec (void)
1900 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1901 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1902 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1904 while (DotProduct(temp, temp) >= 1);
1905 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1912 Returns a color vector indicating the lighting at the requested point.
1914 (Internal Operation note: actually measures the light beneath the point, just like
1915 the model lighting on the client)
1920 void PF_GetLight (void)
1922 vec3_t ambientcolor, diffusecolor, diffusenormal;
1924 p = G_VECTOR(OFS_PARM0);
1925 VectorClear(ambientcolor);
1926 VectorClear(diffusecolor);
1927 VectorClear(diffusenormal);
1928 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1929 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1930 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1933 #define MAX_QC_CVARS 128
1934 cvar_t qc_cvar[MAX_QC_CVARS];
1937 void PF_registercvar (void)
1941 name = G_STRING(OFS_PARM0);
1942 value = G_STRING(OFS_PARM1);
1943 G_FLOAT(OFS_RETURN) = 0;
1944 // first check to see if it has already been defined
1945 if (Cvar_FindVar (name))
1948 // check for overlap with a command
1949 if (Cmd_Exists (name))
1951 Con_Printf ("PF_registercvar: %s is a command\n", name);
1955 if (currentqc_cvar >= MAX_QC_CVARS)
1956 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1958 // copy the name and value
1959 variable = &qc_cvar[currentqc_cvar++];
1960 variable->name = Z_Malloc (strlen(name)+1);
1961 strcpy (variable->name, name);
1962 variable->string = Z_Malloc (strlen(value)+1);
1963 strcpy (variable->string, value);
1964 variable->value = atof (value);
1966 Cvar_RegisterVariable(variable);
1967 G_FLOAT(OFS_RETURN) = 1; // success
1974 returns the minimum of two supplied floats
1981 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1983 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1984 else if (pr_argc >= 3)
1987 float f = G_FLOAT(OFS_PARM0);
1988 for (i = 1;i < pr_argc;i++)
1989 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1990 f = G_FLOAT((OFS_PARM0+i*3));
1991 G_FLOAT(OFS_RETURN) = f;
1994 Host_Error("min: must supply at least 2 floats\n");
2001 returns the maximum of two supplied floats
2008 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2010 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2011 else if (pr_argc >= 3)
2014 float f = G_FLOAT(OFS_PARM0);
2015 for (i = 1;i < pr_argc;i++)
2016 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2017 f = G_FLOAT((OFS_PARM0+i*3));
2018 G_FLOAT(OFS_RETURN) = f;
2021 Host_Error("max: must supply at least 2 floats\n");
2028 returns number bounded by supplied range
2030 min(min, value, max)
2033 void PF_bound (void)
2035 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2042 returns a raised to power b
2049 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2056 copies data from one entity to another
2058 copyentity(src, dst)
2061 void PF_copyentity (void)
2064 in = G_EDICT(OFS_PARM0);
2065 out = G_EDICT(OFS_PARM1);
2066 memcpy(out->v, in->v, progs->entityfields * 4);
2073 sets the color of a client and broadcasts the update to all connected clients
2075 setcolor(clientent, value)
2078 void PF_setcolor (void)
2084 entnum = G_EDICTNUM(OFS_PARM0);
2085 i = G_FLOAT(OFS_PARM1);
2087 if (entnum < 1 || entnum > MAX_SCOREBOARD || !(client = svs.connectedclients[entnum-1]))
2089 Con_Printf ("tried to setcolor a non-client\n");
2093 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2096 client->old_colors = i;
2097 client->edict->v->team = (i & 15) + 1;
2099 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2100 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2101 MSG_WriteByte (&sv.reliable_datagram, i);
2108 effect(origin, modelname, startframe, framecount, framerate)
2111 void PF_effect (void)
2114 s = G_STRING(OFS_PARM1);
2116 Host_Error("effect: no model specified\n");
2118 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2121 void PF_te_blood (void)
2123 if (G_FLOAT(OFS_PARM2) < 1)
2125 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2126 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2128 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2129 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2130 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2132 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2133 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2134 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2136 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2139 void PF_te_bloodshower (void)
2141 if (G_FLOAT(OFS_PARM3) < 1)
2143 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2144 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2146 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2147 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2148 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2150 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2151 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2152 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2154 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2156 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2159 void PF_te_explosionrgb (void)
2161 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2162 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2164 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2165 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2166 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2168 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2169 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2170 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2173 void PF_te_particlecube (void)
2175 if (G_FLOAT(OFS_PARM3) < 1)
2177 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2178 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2180 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2181 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2184 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2185 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2186 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2189 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2190 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2192 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2194 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2195 // gravity true/false
2196 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2198 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2201 void PF_te_particlerain (void)
2203 if (G_FLOAT(OFS_PARM3) < 1)
2205 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2206 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2208 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2209 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2213 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2217 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2218 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2220 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2222 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2225 void PF_te_particlesnow (void)
2227 if (G_FLOAT(OFS_PARM3) < 1)
2229 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2230 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2232 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2237 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2241 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2242 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2244 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2246 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2249 void PF_te_spark (void)
2251 if (G_FLOAT(OFS_PARM2) < 1)
2253 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2254 MSG_WriteByte(&sv.datagram, TE_SPARK);
2256 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2257 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2258 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2260 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2261 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2262 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2264 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2267 void PF_te_gunshotquad (void)
2269 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2270 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2272 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2273 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2274 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2277 void PF_te_spikequad (void)
2279 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2280 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2287 void PF_te_superspikequad (void)
2289 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2290 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2292 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2293 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2294 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2297 void PF_te_explosionquad (void)
2299 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2300 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2302 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2303 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2307 void PF_te_smallflash (void)
2309 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2310 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2312 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2313 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2314 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2317 void PF_te_customflash (void)
2319 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2321 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2322 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2324 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2325 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2326 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2328 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2330 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2332 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2333 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2334 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2337 void PF_te_gunshot (void)
2339 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2340 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2342 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2343 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2344 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2347 void PF_te_spike (void)
2349 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2350 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2353 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2354 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2357 void PF_te_superspike (void)
2359 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2360 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2363 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2364 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2367 void PF_te_explosion (void)
2369 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2370 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2377 void PF_te_tarexplosion (void)
2379 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2380 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2382 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2383 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2384 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2387 void PF_te_wizspike (void)
2389 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2390 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2392 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2393 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2394 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2397 void PF_te_knightspike (void)
2399 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2400 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2402 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2403 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2404 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2407 void PF_te_lavasplash (void)
2409 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2410 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2413 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2414 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2417 void PF_te_teleport (void)
2419 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2420 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2423 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2424 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2427 void PF_te_explosion2 (void)
2429 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2430 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2433 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2434 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2436 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2439 void PF_te_lightning1 (void)
2441 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2442 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2444 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2446 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2447 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2448 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2451 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2452 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2455 void PF_te_lightning2 (void)
2457 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2458 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2460 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2466 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2467 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2468 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2471 void PF_te_lightning3 (void)
2473 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2474 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2476 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2478 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2479 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2483 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2484 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2487 void PF_te_beam (void)
2489 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2490 MSG_WriteByte(&sv.datagram, TE_BEAM);
2492 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2499 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2503 void PF_te_plasmaburn (void)
2505 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2506 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2508 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2509 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2512 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2515 vec3_t v1, clipplanenormal, normal;
2516 vec_t clipplanedist, clipdist;
2518 if (surf->flags & SURF_PLANEBACK)
2519 VectorNegate(surf->plane->normal, normal);
2521 VectorCopy(surf->plane->normal, normal);
2522 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2524 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2525 VectorNormalizeFast(v1);
2526 CrossProduct(v1, normal, clipplanenormal);
2527 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2528 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2531 clipdist = -clipdist;
2532 VectorMA(out, clipdist, clipplanenormal, out);
2537 static msurface_t *getsurface(edict_t *ed, int surfnum)
2541 if (!ed || ed->e->free)
2543 modelindex = ed->v->modelindex;
2544 if (modelindex < 1 || modelindex >= MAX_MODELS)
2546 model = sv.models[modelindex];
2547 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2549 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2553 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2554 void PF_getsurfacenumpoints(void)
2557 // return 0 if no such surface
2558 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2560 G_FLOAT(OFS_RETURN) = 0;
2564 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2566 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2567 void PF_getsurfacepoint(void)
2572 VectorClear(G_VECTOR(OFS_RETURN));
2573 ed = G_EDICT(OFS_PARM0);
2574 if (!ed || ed->e->free)
2576 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2578 pointnum = G_FLOAT(OFS_PARM2);
2579 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2581 // FIXME: implement rotation/scaling
2582 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2584 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2585 void PF_getsurfacenormal(void)
2588 VectorClear(G_VECTOR(OFS_RETURN));
2589 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2591 // FIXME: implement rotation/scaling
2592 if (surf->flags & SURF_PLANEBACK)
2593 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2595 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2597 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2598 void PF_getsurfacetexture(void)
2601 G_INT(OFS_RETURN) = 0;
2602 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2604 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2606 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2607 void PF_getsurfacenearpoint(void)
2609 int surfnum, best, modelindex;
2611 vec_t dist, bestdist;
2616 G_FLOAT(OFS_RETURN) = -1;
2617 ed = G_EDICT(OFS_PARM0);
2618 point = G_VECTOR(OFS_PARM1);
2620 if (!ed || ed->e->free)
2622 modelindex = ed->v->modelindex;
2623 if (modelindex < 1 || modelindex >= MAX_MODELS)
2625 model = sv.models[modelindex];
2626 if (!model->brushq1.numsurfaces)
2629 // FIXME: implement rotation/scaling
2630 VectorSubtract(point, ed->v->origin, p);
2632 bestdist = 1000000000;
2633 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2635 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2636 dist = PlaneDiff(p, surf->plane);
2638 if (dist < bestdist)
2640 clippointtosurface(surf, p, clipped);
2641 VectorSubtract(clipped, p, clipped);
2642 dist += DotProduct(clipped, clipped);
2643 if (dist < bestdist)
2650 G_FLOAT(OFS_RETURN) = best;
2652 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2653 void PF_getsurfaceclippedpoint(void)
2658 VectorClear(G_VECTOR(OFS_RETURN));
2659 ed = G_EDICT(OFS_PARM0);
2660 if (!ed || ed->e->free)
2662 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2664 // FIXME: implement rotation/scaling
2665 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2666 clippointtosurface(surf, p, out);
2667 // FIXME: implement rotation/scaling
2668 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2671 #define MAX_PRFILES 256
2673 qfile_t *pr_files[MAX_PRFILES];
2675 void PR_Files_Init(void)
2677 memset(pr_files, 0, sizeof(pr_files));
2680 void PR_Files_CloseAll(void)
2683 for (i = 0;i < MAX_PRFILES;i++)
2686 FS_Close(pr_files[i]);
2691 //float(string s) stof = #81; // get numerical value from a string
2694 char *s = PF_VarString(0);
2695 G_FLOAT(OFS_RETURN) = atof(s);
2698 //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
2702 char *modestring, *filename;
2703 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2704 if (pr_files[filenum] == NULL)
2706 if (filenum >= MAX_PRFILES)
2708 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2709 G_FLOAT(OFS_RETURN) = -2;
2712 mode = G_FLOAT(OFS_PARM1);
2715 case 0: // FILE_READ
2718 case 1: // FILE_APPEND
2721 case 2: // FILE_WRITE
2725 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2726 G_FLOAT(OFS_RETURN) = -3;
2729 filename = G_STRING(OFS_PARM0);
2730 // .. is parent directory on many platforms
2731 // / is parent directory on Amiga
2732 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2733 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2734 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2736 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2737 G_FLOAT(OFS_RETURN) = -4;
2740 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2741 if (pr_files[filenum] == NULL)
2742 G_FLOAT(OFS_RETURN) = -1;
2744 G_FLOAT(OFS_RETURN) = filenum;
2747 //void(float fhandle) fclose = #111; // closes a file
2748 void PF_fclose(void)
2750 int filenum = G_FLOAT(OFS_PARM0);
2751 if (filenum < 0 || filenum >= MAX_PRFILES)
2753 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2756 if (pr_files[filenum] == NULL)
2758 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2761 FS_Close(pr_files[filenum]);
2762 pr_files[filenum] = NULL;
2765 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2769 static char string[MAX_VARSTRING];
2770 int filenum = G_FLOAT(OFS_PARM0);
2771 if (filenum < 0 || filenum >= MAX_PRFILES)
2773 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2776 if (pr_files[filenum] == NULL)
2778 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2784 c = FS_Getc(pr_files[filenum]);
2785 if (c == '\r' || c == '\n' || c < 0)
2787 if (end < MAX_VARSTRING - 1)
2791 // remove \n following \r
2793 c = FS_Getc(pr_files[filenum]);
2794 if (developer.integer)
2795 Con_Printf("fgets: %s\n", string);
2797 G_INT(OFS_RETURN) = PR_SetString(string);
2799 G_INT(OFS_RETURN) = 0;
2802 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2806 char *s = PF_VarString(1);
2807 int filenum = G_FLOAT(OFS_PARM0);
2808 if (filenum < 0 || filenum >= MAX_PRFILES)
2810 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2813 if (pr_files[filenum] == NULL)
2815 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2818 if ((stringlength = strlen(s)))
2819 FS_Write(pr_files[filenum], s, stringlength);
2820 if (developer.integer)
2821 Con_Printf("fputs: %s\n", s);
2824 //float(string s) strlen = #114; // returns how many characters are in a string
2825 void PF_strlen(void)
2828 s = G_STRING(OFS_PARM0);
2830 G_FLOAT(OFS_RETURN) = strlen(s);
2832 G_FLOAT(OFS_RETURN) = 0;
2835 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2836 void PF_strcat(void)
2838 char *s = PF_VarString(0);
2839 G_INT(OFS_RETURN) = PR_SetString(s);
2842 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2843 void PF_substring(void)
2845 int i, start, length;
2846 char *s, *string = PR_GetTempString();
2847 s = G_STRING(OFS_PARM0);
2848 start = G_FLOAT(OFS_PARM1);
2849 length = G_FLOAT(OFS_PARM2);
2852 for (i = 0;i < start && *s;i++, s++);
2853 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2856 G_INT(OFS_RETURN) = PR_SetString(string);
2859 //vector(string s) stov = #117; // returns vector value from a string
2862 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2865 //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)
2866 void PF_strzone(void)
2869 in = G_STRING(OFS_PARM0);
2870 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2872 G_INT(OFS_RETURN) = PR_SetString(out);
2875 //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!!!)
2876 void PF_strunzone(void)
2878 Mem_Free(G_STRING(OFS_PARM0));
2881 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2882 //this function originally written by KrimZon, made shorter by LordHavoc
2883 void PF_clientcommand (void)
2885 client_t *temp_client;
2888 //find client for this entity
2889 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2890 if (i < 0 || i >= MAX_SCOREBOARD || !svs.connectedclients[i])
2891 Host_Error("PF_clientcommand: entity is not a client");
2893 temp_client = host_client;
2894 host_client = svs.connectedclients[i];
2895 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2896 host_client = temp_client;
2899 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2900 //this function originally written by KrimZon, made shorter by LordHavoc
2901 char **tokens = NULL;
2902 int max_tokens, num_tokens = 0;
2903 void PF_tokenize (void)
2907 str = G_STRING(OFS_PARM0);
2912 for (i=0;i<num_tokens;i++)
2918 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2919 max_tokens = strlen(str);
2921 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2923 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2924 strcpy(tokens[num_tokens], com_token);
2927 G_FLOAT(OFS_RETURN) = num_tokens;
2930 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2931 //this function originally written by KrimZon, made shorter by LordHavoc
2934 int token_num = G_FLOAT(OFS_PARM0);
2935 if (token_num >= 0 && token_num < num_tokens)
2936 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2938 G_INT(OFS_RETURN) = PR_SetString("");
2941 //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)
2942 void PF_setattachment (void)
2944 edict_t *e = G_EDICT(OFS_PARM0);
2945 edict_t *tagentity = G_EDICT(OFS_PARM1);
2946 char *tagname = G_STRING(OFS_PARM2);
2951 if (tagentity == NULL)
2952 tagentity = sv.edicts;
2954 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2956 v->edict = EDICT_TO_PROG(tagentity);
2958 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2961 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2963 modelindex = (int)tagentity->v->modelindex;
2964 if (modelindex >= 0 && modelindex < MAX_MODELS)
2966 model = sv.models[modelindex];
2967 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2968 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2969 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2971 if (v->_float == 0 && model->alias.aliasnum_tags)
2972 for (i = 0;i < model->alias.aliasnum_tags;i++)
2973 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2976 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);
2979 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));
2984 builtin_t pr_builtin[] =
2987 PF_makevectors, // #1 void(entity e) makevectors
2988 PF_setorigin, // #2 void(entity e, vector o) setorigin
2989 PF_setmodel, // #3 void(entity e, string m) setmodel
2990 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2991 NULL, // #5 void(entity e, vector min, vector max) setabssize
2992 PF_break, // #6 void() break
2993 PF_random, // #7 float() random
2994 PF_sound, // #8 void(entity e, float chan, string samp) sound
2995 PF_normalize, // #9 vector(vector v) normalize
2996 PF_error, // #10 void(string e) error
2997 PF_objerror, // #11 void(string e) objerror
2998 PF_vlen, // #12 float(vector v) vlen
2999 PF_vectoyaw, // #13 float(vector v) vectoyaw
3000 PF_Spawn, // #14 entity() spawn
3001 PF_Remove, // #15 void(entity e) remove
3002 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3003 PF_checkclient, // #17 entity() clientlist
3004 PF_Find, // #18 entity(entity start, .string fld, string match) find
3005 PF_precache_sound, // #19 void(string s) precache_sound
3006 PF_precache_model, // #20 void(string s) precache_model
3007 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3008 PF_findradius, // #22 entity(vector org, float rad) findradius
3009 PF_bprint, // #23 void(string s) bprint
3010 PF_sprint, // #24 void(entity client, string s) sprint
3011 PF_dprint, // #25 void(string s) dprint
3012 PF_ftos, // #26 void(string s) ftos
3013 PF_vtos, // #27 void(string s) vtos
3014 PF_coredump, // #28 void() coredump
3015 PF_traceon, // #29 void() traceon
3016 PF_traceoff, // #30 void() traceoff
3017 PF_eprint, // #31 void(entity e) eprint
3018 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3020 PF_droptofloor, // #34 float() droptofloor
3021 PF_lightstyle, // #35 void(float style, string value) lightstyle
3022 PF_rint, // #36 float(float v) rint
3023 PF_floor, // #37 float(float v) floor
3024 PF_ceil, // #38 float(float v) ceil
3026 PF_checkbottom, // #40 float(entity e) checkbottom
3027 PF_pointcontents , // #41 float(vector v) pointcontents
3029 PF_fabs, // #43 float(float f) fabs
3030 PF_aim, // #44 vector(entity e, float speed) aim
3031 PF_cvar, // #45 float(string s) cvar
3032 PF_localcmd, // #46 void(string s) localcmd
3033 PF_nextent, // #47 entity(entity e) nextent
3034 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3035 PF_changeyaw, // #49 void() ChangeYaw
3037 PF_vectoangles, // #51 vector(vector v) vectoangles
3038 PF_WriteByte, // #52 void(float to, float f) WriteByte
3039 PF_WriteChar, // #53 void(float to, float f) WriteChar
3040 PF_WriteShort, // #54 void(float to, float f) WriteShort
3041 PF_WriteLong, // #55 void(float to, float f) WriteLong
3042 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3043 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3044 PF_WriteString, // #58 void(float to, string s) WriteString
3045 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3046 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3047 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3048 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3049 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3050 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3051 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3053 SV_MoveToGoal, // #67 void(float step) movetogoal
3054 PF_precache_file, // #68 string(string s) precache_file
3055 PF_makestatic, // #69 void(entity e) makestatic
3056 PF_changelevel, // #70 void(string s) changelevel
3058 PF_cvar_set, // #72 void(string var, string val) cvar_set
3059 PF_centerprint, // #73 void(entity client, strings) centerprint
3060 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3061 PF_precache_model, // #75 string(string s) precache_model2
3062 PF_precache_sound, // #76 string(string s) precache_sound2
3063 PF_precache_file, // #77 string(string s) precache_file2
3064 PF_setspawnparms, // #78 void(entity e) setspawnparms
3067 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3076 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3077 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3078 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3079 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3080 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3081 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3082 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3083 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3084 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3085 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3096 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3097 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3098 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3099 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3100 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3101 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3102 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3103 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3104 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3105 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3106 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3107 a a a a a a a a // #120-199
3108 a a a a a a a a a a // #200-299
3109 a a a a a a a a a a // #300-399
3110 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3111 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3112 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3113 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3114 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3115 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3116 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3117 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3118 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3119 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3120 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3121 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3122 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3123 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3124 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3125 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3126 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3127 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3128 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3129 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3130 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3131 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3132 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3133 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3134 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3135 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3136 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3137 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3138 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3139 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3140 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3141 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3142 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3143 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3144 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3145 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3146 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3147 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3148 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3149 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3150 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3151 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3152 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3153 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3160 a a a a a // #450-499 (LordHavoc)
3163 builtin_t *pr_builtins = pr_builtin;
3164 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3166 void PR_Cmd_Init(void)
3168 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3172 void PR_Cmd_Reset(void)
3174 Mem_EmptyPool(pr_strings_mempool);
3175 PR_Files_CloseAll();