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 // LordHavoc: ftos improvement
1074 sprintf (s, "%g", v);
1075 G_INT(OFS_RETURN) = PR_SetString(s);
1081 v = G_FLOAT(OFS_PARM0);
1082 G_FLOAT(OFS_RETURN) = fabs(v);
1088 s = PR_GetTempString();
1089 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1090 G_INT(OFS_RETURN) = PR_SetString(s);
1096 s = PR_GetTempString();
1097 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1098 G_INT(OFS_RETURN) = PR_SetString(s);
1101 void PF_Spawn (void)
1104 pr_xfunction->builtinsprofile += 20;
1109 void PF_Remove (void)
1112 pr_xfunction->builtinsprofile += 20;
1114 ed = G_EDICT(OFS_PARM0);
1115 if (ed == sv.edicts)
1116 Host_Error("remove: tried to remove world\n");
1117 if (NUM_FOR_EDICT(ed) <= MAX_SCOREBOARD)
1118 Host_Error("remove: tried to remove a client\n");
1123 // entity (entity start, .string field, string match) find = #5;
1131 e = G_EDICTNUM(OFS_PARM0);
1132 f = G_INT(OFS_PARM1);
1133 s = G_STRING(OFS_PARM2);
1136 RETURN_EDICT(sv.edicts);
1140 for (e++ ; e < sv.num_edicts ; e++)
1142 pr_xfunction->builtinsprofile++;
1156 RETURN_EDICT(sv.edicts);
1159 // LordHavoc: added this for searching float, int, and entity reference fields
1160 void PF_FindFloat (void)
1167 e = G_EDICTNUM(OFS_PARM0);
1168 f = G_INT(OFS_PARM1);
1169 s = G_FLOAT(OFS_PARM2);
1171 for (e++ ; e < sv.num_edicts ; e++)
1173 pr_xfunction->builtinsprofile++;
1177 if (E_FLOAT(ed,f) == s)
1184 RETURN_EDICT(sv.edicts);
1187 // chained search for strings in entity fields
1188 // entity(.string field, string match) findchain = #402;
1189 void PF_findchain (void)
1194 edict_t *ent, *chain;
1196 chain = (edict_t *)sv.edicts;
1198 f = G_INT(OFS_PARM0);
1199 s = G_STRING(OFS_PARM1);
1202 RETURN_EDICT(sv.edicts);
1206 ent = NEXT_EDICT(sv.edicts);
1207 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1209 pr_xfunction->builtinsprofile++;
1212 t = E_STRING(ent,f);
1218 ent->v->chain = EDICT_TO_PROG(chain);
1222 RETURN_EDICT(chain);
1225 // LordHavoc: chained search for float, int, and entity reference fields
1226 // entity(.string field, float match) findchainfloat = #403;
1227 void PF_findchainfloat (void)
1232 edict_t *ent, *chain;
1234 chain = (edict_t *)sv.edicts;
1236 f = G_INT(OFS_PARM0);
1237 s = G_FLOAT(OFS_PARM1);
1239 ent = NEXT_EDICT(sv.edicts);
1240 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1242 pr_xfunction->builtinsprofile++;
1245 if (E_FLOAT(ent,f) != s)
1248 ent->v->chain = EDICT_TO_PROG(chain);
1252 RETURN_EDICT(chain);
1255 void PR_CheckEmptyString (char *s)
1258 Host_Error ("Bad string");
1261 void PF_precache_file (void)
1262 { // precache_file is only used to copy files with qcc, it does nothing
1263 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1266 void PF_precache_sound (void)
1271 if (sv.state != ss_loading)
1272 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1274 s = G_STRING(OFS_PARM0);
1275 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1276 PR_CheckEmptyString (s);
1278 for (i=0 ; i<MAX_SOUNDS ; i++)
1280 if (!sv.sound_precache[i])
1282 sv.sound_precache[i] = s;
1285 if (!strcmp(sv.sound_precache[i], s))
1288 Host_Error ("PF_precache_sound: overflow");
1291 void PF_precache_model (void)
1296 if (sv.state != ss_loading)
1297 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1299 s = G_STRING(OFS_PARM0);
1300 if (sv.worldmodel->brushq1.ishlbsp && ((!s) || (!s[0])))
1302 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1303 PR_CheckEmptyString (s);
1305 for (i=0 ; i<MAX_MODELS ; i++)
1307 if (!sv.model_precache[i])
1309 sv.model_precache[i] = s;
1310 sv.models[i] = Mod_ForName (s, true, false, false);
1313 if (!strcmp(sv.model_precache[i], s))
1316 Host_Error ("PF_precache_model: overflow");
1320 void PF_coredump (void)
1325 void PF_traceon (void)
1330 void PF_traceoff (void)
1335 void PF_eprint (void)
1337 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1344 float(float yaw, float dist) walkmove
1347 void PF_walkmove (void)
1355 ent = PROG_TO_EDICT(pr_global_struct->self);
1356 yaw = G_FLOAT(OFS_PARM0);
1357 dist = G_FLOAT(OFS_PARM1);
1359 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1361 G_FLOAT(OFS_RETURN) = 0;
1365 yaw = yaw*M_PI*2 / 360;
1367 move[0] = cos(yaw)*dist;
1368 move[1] = sin(yaw)*dist;
1371 // save program state, because SV_movestep may call other progs
1372 oldf = pr_xfunction;
1373 oldself = pr_global_struct->self;
1375 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1378 // restore program state
1379 pr_xfunction = oldf;
1380 pr_global_struct->self = oldself;
1390 void PF_droptofloor (void)
1396 ent = PROG_TO_EDICT(pr_global_struct->self);
1398 VectorCopy (ent->v->origin, end);
1401 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1403 if (trace.fraction == 1)
1404 G_FLOAT(OFS_RETURN) = 0;
1407 VectorCopy (trace.endpos, ent->v->origin);
1408 SV_LinkEdict (ent, false);
1409 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1410 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1411 G_FLOAT(OFS_RETURN) = 1;
1412 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1413 ent->e->suspendedinairflag = true;
1421 void(float style, string value) lightstyle
1424 void PF_lightstyle (void)
1431 style = G_FLOAT(OFS_PARM0);
1432 val = G_STRING(OFS_PARM1);
1434 // change the string in sv
1435 sv.lightstyles[style] = val;
1437 // send message to all clients on this server
1438 if (sv.state != ss_active)
1441 for (j = 0;j < MAX_SCOREBOARD;j++)
1443 if ((client = svs.connectedclients[j]))
1445 MSG_WriteChar (&client->message, svc_lightstyle);
1446 MSG_WriteChar (&client->message,style);
1447 MSG_WriteString (&client->message, val);
1455 f = G_FLOAT(OFS_PARM0);
1457 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1459 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1461 void PF_floor (void)
1463 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1467 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1476 void PF_checkbottom (void)
1478 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1486 void PF_pointcontents (void)
1488 G_FLOAT(OFS_RETURN) = SV_PointContents(G_VECTOR(OFS_PARM0));
1495 entity nextent(entity)
1498 void PF_nextent (void)
1503 i = G_EDICTNUM(OFS_PARM0);
1506 pr_xfunction->builtinsprofile++;
1508 if (i == sv.num_edicts)
1510 RETURN_EDICT(sv.edicts);
1526 Pick a vector for the player to shoot along
1527 vector aim(entity, missilespeed)
1532 edict_t *ent, *check, *bestent;
1533 vec3_t start, dir, end, bestdir;
1536 float dist, bestdist;
1539 ent = G_EDICT(OFS_PARM0);
1540 speed = G_FLOAT(OFS_PARM1);
1542 VectorCopy (ent->v->origin, start);
1545 // try sending a trace straight
1546 VectorCopy (pr_global_struct->v_forward, dir);
1547 VectorMA (start, 2048, dir, end);
1548 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1549 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1550 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1552 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1557 // try all possible entities
1558 VectorCopy (dir, bestdir);
1559 bestdist = sv_aim.value;
1562 check = NEXT_EDICT(sv.edicts);
1563 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1565 pr_xfunction->builtinsprofile++;
1566 if (check->v->takedamage != DAMAGE_AIM)
1570 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1571 continue; // don't aim at teammate
1572 for (j=0 ; j<3 ; j++)
1573 end[j] = check->v->origin[j]
1574 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1575 VectorSubtract (end, start, dir);
1576 VectorNormalize (dir);
1577 dist = DotProduct (dir, pr_global_struct->v_forward);
1578 if (dist < bestdist)
1579 continue; // to far to turn
1580 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1581 if (tr.ent == check)
1582 { // can shoot at this one
1590 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1591 dist = DotProduct (dir, pr_global_struct->v_forward);
1592 VectorScale (pr_global_struct->v_forward, dist, end);
1594 VectorNormalize (end);
1595 VectorCopy (end, G_VECTOR(OFS_RETURN));
1599 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1607 This was a major timewaster in progs, so it was converted to C
1610 void PF_changeyaw (void)
1613 float ideal, current, move, speed;
1615 ent = PROG_TO_EDICT(pr_global_struct->self);
1616 current = ANGLEMOD(ent->v->angles[1]);
1617 ideal = ent->v->ideal_yaw;
1618 speed = ent->v->yaw_speed;
1620 if (current == ideal)
1622 move = ideal - current;
1623 if (ideal > current)
1644 ent->v->angles[1] = ANGLEMOD (current + move);
1652 void PF_changepitch (void)
1655 float ideal, current, move, speed;
1658 ent = G_EDICT(OFS_PARM0);
1659 current = ANGLEMOD( ent->v->angles[0] );
1660 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1661 ideal = val->_float;
1664 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1667 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1668 speed = val->_float;
1671 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1675 if (current == ideal)
1677 move = ideal - current;
1678 if (ideal > current)
1699 ent->v->angles[0] = ANGLEMOD (current + move);
1703 ===============================================================================
1707 ===============================================================================
1710 #define MSG_BROADCAST 0 // unreliable to all
1711 #define MSG_ONE 1 // reliable to one (msg_entity)
1712 #define MSG_ALL 2 // reliable to all
1713 #define MSG_INIT 3 // write to the init string
1715 sizebuf_t *WriteDest (void)
1721 dest = G_FLOAT(OFS_PARM0);
1725 return &sv.datagram;
1728 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1729 entnum = NUM_FOR_EDICT(ent);
1730 if (entnum < 1 || entnum > MAX_SCOREBOARD || svs.connectedclients[entnum-1] == NULL)
1731 Host_Error("WriteDest: not a client");
1732 return &svs.connectedclients[entnum-1]->message;
1735 return &sv.reliable_datagram;
1741 Host_Error ("WriteDest: bad destination");
1748 void PF_WriteByte (void)
1750 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1753 void PF_WriteChar (void)
1755 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1758 void PF_WriteShort (void)
1760 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1763 void PF_WriteLong (void)
1765 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1768 void PF_WriteAngle (void)
1770 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1773 void PF_WriteCoord (void)
1775 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1778 void PF_WriteString (void)
1780 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1784 void PF_WriteEntity (void)
1786 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1789 //=============================================================================
1791 void PF_makestatic (void)
1796 ent = G_EDICT(OFS_PARM0);
1799 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1804 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1805 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1806 MSG_WriteShort (&sv.signon, ent->v->frame);
1810 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1811 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1812 MSG_WriteByte (&sv.signon, ent->v->frame);
1815 MSG_WriteByte (&sv.signon, ent->v->colormap);
1816 MSG_WriteByte (&sv.signon, ent->v->skin);
1817 for (i=0 ; i<3 ; i++)
1819 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1820 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1823 // throw the entity away now
1827 //=============================================================================
1834 void PF_setspawnparms (void)
1840 ent = G_EDICT(OFS_PARM0);
1841 i = NUM_FOR_EDICT(ent);
1842 if (i < 1 || i > MAX_SCOREBOARD || !svs.connectedclients[i-1])
1843 Host_Error ("Entity is not a client");
1845 // copy spawn parms out of the client_t
1846 client = svs.connectedclients[i-1];
1847 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1848 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1856 void PF_changelevel (void)
1860 // make sure we don't issue two changelevels
1861 if (svs.changelevel_issued)
1863 svs.changelevel_issued = true;
1865 s = G_STRING(OFS_PARM0);
1866 Cbuf_AddText (va("changelevel %s\n",s));
1871 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1876 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1881 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1888 Returns a vector of length < 1
1893 void PF_randomvec (void)
1898 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1899 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1900 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1902 while (DotProduct(temp, temp) >= 1);
1903 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1910 Returns a color vector indicating the lighting at the requested point.
1912 (Internal Operation note: actually measures the light beneath the point, just like
1913 the model lighting on the client)
1918 void PF_GetLight (void)
1920 vec3_t ambientcolor, diffusecolor, diffusenormal;
1922 p = G_VECTOR(OFS_PARM0);
1923 VectorClear(ambientcolor);
1924 VectorClear(diffusecolor);
1925 VectorClear(diffusenormal);
1926 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1927 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1928 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1931 #define MAX_QC_CVARS 128
1932 cvar_t qc_cvar[MAX_QC_CVARS];
1935 void PF_registercvar (void)
1939 name = G_STRING(OFS_PARM0);
1940 value = G_STRING(OFS_PARM1);
1941 G_FLOAT(OFS_RETURN) = 0;
1942 // first check to see if it has already been defined
1943 if (Cvar_FindVar (name))
1946 // check for overlap with a command
1947 if (Cmd_Exists (name))
1949 Con_Printf ("PF_registercvar: %s is a command\n", name);
1953 if (currentqc_cvar >= MAX_QC_CVARS)
1954 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1956 // copy the name and value
1957 variable = &qc_cvar[currentqc_cvar++];
1958 variable->name = Z_Malloc (strlen(name)+1);
1959 strcpy (variable->name, name);
1960 variable->string = Z_Malloc (strlen(value)+1);
1961 strcpy (variable->string, value);
1962 variable->value = atof (value);
1964 Cvar_RegisterVariable(variable);
1965 G_FLOAT(OFS_RETURN) = 1; // success
1972 returns the minimum of two supplied floats
1979 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1981 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1982 else if (pr_argc >= 3)
1985 float f = G_FLOAT(OFS_PARM0);
1986 for (i = 1;i < pr_argc;i++)
1987 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1988 f = G_FLOAT((OFS_PARM0+i*3));
1989 G_FLOAT(OFS_RETURN) = f;
1992 Host_Error("min: must supply at least 2 floats\n");
1999 returns the maximum of two supplied floats
2006 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2008 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2009 else if (pr_argc >= 3)
2012 float f = G_FLOAT(OFS_PARM0);
2013 for (i = 1;i < pr_argc;i++)
2014 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2015 f = G_FLOAT((OFS_PARM0+i*3));
2016 G_FLOAT(OFS_RETURN) = f;
2019 Host_Error("max: must supply at least 2 floats\n");
2026 returns number bounded by supplied range
2028 min(min, value, max)
2031 void PF_bound (void)
2033 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2040 returns a raised to power b
2047 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2054 copies data from one entity to another
2056 copyentity(src, dst)
2059 void PF_copyentity (void)
2062 in = G_EDICT(OFS_PARM0);
2063 out = G_EDICT(OFS_PARM1);
2064 memcpy(out->v, in->v, progs->entityfields * 4);
2071 sets the color of a client and broadcasts the update to all connected clients
2073 setcolor(clientent, value)
2076 void PF_setcolor (void)
2082 entnum = G_EDICTNUM(OFS_PARM0);
2083 i = G_FLOAT(OFS_PARM1);
2085 if (entnum < 1 || entnum > MAX_SCOREBOARD || !(client = svs.connectedclients[entnum-1]))
2087 Con_Printf ("tried to setcolor a non-client\n");
2091 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2094 client->old_colors = i;
2095 client->edict->v->team = (i & 15) + 1;
2097 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2098 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2099 MSG_WriteByte (&sv.reliable_datagram, i);
2106 effect(origin, modelname, startframe, framecount, framerate)
2109 void PF_effect (void)
2112 s = G_STRING(OFS_PARM1);
2114 Host_Error("effect: no model specified\n");
2116 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2119 void PF_te_blood (void)
2121 if (G_FLOAT(OFS_PARM2) < 1)
2123 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2124 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2126 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2127 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2128 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2130 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2131 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2132 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2134 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2137 void PF_te_bloodshower (void)
2139 if (G_FLOAT(OFS_PARM3) < 1)
2141 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2142 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2144 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2145 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2146 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2148 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2149 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2150 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2152 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2154 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2157 void PF_te_explosionrgb (void)
2159 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2160 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2162 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2163 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2164 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2166 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2167 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2168 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2171 void PF_te_particlecube (void)
2173 if (G_FLOAT(OFS_PARM3) < 1)
2175 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2176 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2179 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2180 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2184 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2186 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2190 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2192 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2193 // gravity true/false
2194 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2196 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2199 void PF_te_particlerain (void)
2201 if (G_FLOAT(OFS_PARM3) < 1)
2203 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2204 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2206 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2207 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2208 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2218 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2220 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2223 void PF_te_particlesnow (void)
2225 if (G_FLOAT(OFS_PARM3) < 1)
2227 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2228 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2231 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2232 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2242 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2244 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2247 void PF_te_spark (void)
2249 if (G_FLOAT(OFS_PARM2) < 1)
2251 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2252 MSG_WriteByte(&sv.datagram, TE_SPARK);
2254 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2255 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2256 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2258 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2259 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2260 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2262 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2265 void PF_te_gunshotquad (void)
2267 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2268 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2270 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2271 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2272 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2275 void PF_te_spikequad (void)
2277 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2280 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2285 void PF_te_superspikequad (void)
2287 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2288 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2290 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2292 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2295 void PF_te_explosionquad (void)
2297 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2298 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2300 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2301 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2302 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2305 void PF_te_smallflash (void)
2307 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2308 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2310 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2312 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2315 void PF_te_customflash (void)
2317 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2319 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2320 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2322 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2323 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2324 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2326 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2328 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2330 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2331 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2332 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2335 void PF_te_gunshot (void)
2337 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2338 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2340 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2341 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2342 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2345 void PF_te_spike (void)
2347 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2350 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2355 void PF_te_superspike (void)
2357 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2358 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2360 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2365 void PF_te_explosion (void)
2367 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2368 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2370 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2375 void PF_te_tarexplosion (void)
2377 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2378 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2380 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2381 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2382 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2385 void PF_te_wizspike (void)
2387 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2388 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2390 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2392 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2395 void PF_te_knightspike (void)
2397 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2398 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2400 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2402 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2405 void PF_te_lavasplash (void)
2407 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2408 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2410 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2415 void PF_te_teleport (void)
2417 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2420 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2425 void PF_te_explosion2 (void)
2427 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2428 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2430 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2434 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2437 void PF_te_lightning1 (void)
2439 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2440 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2442 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2445 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2446 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2448 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2453 void PF_te_lightning2 (void)
2455 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2456 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2458 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2465 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2466 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2469 void PF_te_lightning3 (void)
2471 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2472 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2474 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2477 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2478 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2485 void PF_te_beam (void)
2487 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2488 MSG_WriteByte(&sv.datagram, TE_BEAM);
2490 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2501 void PF_te_plasmaburn (void)
2503 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2504 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2505 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2510 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2513 vec3_t v1, clipplanenormal, normal;
2514 vec_t clipplanedist, clipdist;
2516 if (surf->flags & SURF_PLANEBACK)
2517 VectorNegate(surf->plane->normal, normal);
2519 VectorCopy(surf->plane->normal, normal);
2520 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2522 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2523 VectorNormalizeFast(v1);
2524 CrossProduct(v1, normal, clipplanenormal);
2525 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2526 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2529 clipdist = -clipdist;
2530 VectorMA(out, clipdist, clipplanenormal, out);
2535 static msurface_t *getsurface(edict_t *ed, int surfnum)
2539 if (!ed || ed->e->free)
2541 modelindex = ed->v->modelindex;
2542 if (modelindex < 1 || modelindex >= MAX_MODELS)
2544 model = sv.models[modelindex];
2545 if (model->type != mod_brush)
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->type != mod_brush)
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();