2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
26 mempool_t *pr_strings_mempool;
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
34 static char *PR_GetTempString(void)
37 s = pr_string_temp[pr_string_tempindex];
38 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
42 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
46 ===============================================================================
50 ===============================================================================
54 void PF_VarString(int first, char *out, int outlength)
60 outend = out + outlength - 1;
61 for (i = first;i < pr_argc && out < outend;i++)
63 s = G_STRING((OFS_PARM0+i*3));
64 while (out < outend && *s)
70 char *ENGINE_EXTENSIONS =
80 "DP_ENT_CUSTOMCOLORMAP "
81 "DP_ENT_EXTERIORMODELTOCLIENT "
82 "DP_ENT_LOWPRECISION "
86 "DP_GFX_EXTERNALTEXTURES "
88 "DP_GFX_QUAKE3MODELTAGS "
92 "DP_HALFLIFE_MAP_CVAR "
95 "DP_MOVETYPEBOUNCEMISSILE "
101 "DP_QC_FINDCHAINFLOAT "
107 "DP_QC_SINCOSSQRTPOW "
110 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
111 "DP_QC_TRACE_MOVETYPE_HITMODEL "
112 "DP_QC_VECTORVECTORS "
118 "DP_SV_DRAWONLYTOCLIENT "
120 "DP_SV_EXTERIORMODELTOCLIENT "
121 "DP_SV_NODRAWTOCLIENT "
122 "DP_SV_PLAYERPHYSICS "
128 "DP_TE_EXPLOSIONRGB "
130 "DP_TE_PARTICLECUBE "
131 "DP_TE_PARTICLERAIN "
132 "DP_TE_PARTICLESNOW "
134 "DP_TE_QUADEFFECTS1 "
137 "DP_TE_STANDARDEFFECTBUILTINS "
140 "KRIMZON_SV_PARSECLIENTCOMMAND "
146 qboolean checkextension(char *name)
151 for (e = ENGINE_EXTENSIONS;*e;e++)
158 while (*e && *e != ' ')
160 if (e - start == len)
161 if (!strncasecmp(start, name, len))
171 returns true if the extension is supported by the server
173 checkextension(extensionname)
176 void PF_checkextension (void)
178 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
185 This is a TERMINAL error, which will kill off the entire server.
194 char string[STRINGTEMP_LENGTH];
196 PF_VarString(0, string, sizeof(string));
197 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
198 ed = PROG_TO_EDICT(pr_global_struct->self);
201 Host_Error ("Program error");
208 Dumps out self, then an error message. The program is aborted and self is
209 removed, but the level can continue.
214 void PF_objerror (void)
217 char string[STRINGTEMP_LENGTH];
219 PF_VarString(0, string, sizeof(string));
220 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
221 ed = PROG_TO_EDICT(pr_global_struct->self);
231 Writes new values for v_forward, v_up, and v_right based on angles
235 void PF_makevectors (void)
237 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
244 Writes new values for v_forward, v_up, and v_right based on the given forward vector
245 vectorvectors(vector, vector)
248 void PF_vectorvectors (void)
250 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
251 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
258 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.
260 setorigin (entity, origin)
263 void PF_setorigin (void)
268 e = G_EDICT(OFS_PARM0);
269 org = G_VECTOR(OFS_PARM1);
270 VectorCopy (org, e->v->origin);
271 SV_LinkEdict (e, false);
275 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
279 for (i=0 ; i<3 ; i++)
281 Host_Error ("backwards mins/maxs");
283 // set derived values
284 VectorCopy (min, e->v->mins);
285 VectorCopy (max, e->v->maxs);
286 VectorSubtract (max, min, e->v->size);
288 SV_LinkEdict (e, false);
295 the size box is rotated by the current angle
296 LordHavoc: no it isn't...
298 setsize (entity, minvector, maxvector)
301 void PF_setsize (void)
306 e = G_EDICT(OFS_PARM0);
307 min = G_VECTOR(OFS_PARM1);
308 max = G_VECTOR(OFS_PARM2);
309 SetMinMaxSize (e, min, max, false);
317 setmodel(entity, model)
320 void PF_setmodel (void)
327 e = G_EDICT(OFS_PARM0);
328 m = G_STRING(OFS_PARM1);
330 // check to see if model was properly precached
331 for (i=0, check = sv.model_precache ; *check ; i++, check++)
332 if (!strcmp(*check, m))
336 Host_Error ("no precache: %s\n", m);
339 e->v->model = PR_SetString(*check);
340 e->v->modelindex = i;
342 mod = sv.models[ (int)e->v->modelindex];
345 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
347 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
354 broadcast print to everyone on server
359 void PF_bprint (void)
361 char string[STRINGTEMP_LENGTH];
362 PF_VarString(0, string, sizeof(string));
363 SV_BroadcastPrintf("%s", string);
370 single print to a specific client
372 sprint(clientent, value)
375 void PF_sprint (void)
379 char string[STRINGTEMP_LENGTH];
381 entnum = G_EDICTNUM(OFS_PARM0);
383 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
385 Con_Printf ("tried to sprint to a non-client\n");
389 client = svs.clients + entnum-1;
390 if (!client->netconnection)
392 PF_VarString(1, string, sizeof(string));
393 MSG_WriteChar(&client->message,svc_print);
394 MSG_WriteString(&client->message, string);
402 single print to a specific client
404 centerprint(clientent, value)
407 void PF_centerprint (void)
411 char string[STRINGTEMP_LENGTH];
413 entnum = G_EDICTNUM(OFS_PARM0);
415 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
417 Con_Printf ("tried to sprint to a non-client\n");
421 client = svs.clients + entnum-1;
422 if (!client->netconnection)
424 PF_VarString(1, string, sizeof(string));
425 MSG_WriteChar(&client->message,svc_centerprint);
426 MSG_WriteString(&client->message, string);
434 vector normalize(vector)
437 void PF_normalize (void)
443 value1 = G_VECTOR(OFS_PARM0);
445 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
449 newvalue[0] = newvalue[1] = newvalue[2] = 0;
453 newvalue[0] = value1[0] * new;
454 newvalue[1] = value1[1] * new;
455 newvalue[2] = value1[2] * new;
458 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
473 value1 = G_VECTOR(OFS_PARM0);
475 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
478 G_FLOAT(OFS_RETURN) = new;
485 float vectoyaw(vector)
488 void PF_vectoyaw (void)
493 value1 = G_VECTOR(OFS_PARM0);
495 if (value1[1] == 0 && value1[0] == 0)
499 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
504 G_FLOAT(OFS_RETURN) = yaw;
512 vector vectoangles(vector)
515 void PF_vectoangles (void)
521 value1 = G_VECTOR(OFS_PARM0);
523 if (value1[1] == 0 && value1[0] == 0)
533 // LordHavoc: optimized a bit
536 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
540 else if (value1[1] > 0)
545 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
546 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
551 G_FLOAT(OFS_RETURN+0) = pitch;
552 G_FLOAT(OFS_RETURN+1) = yaw;
553 G_FLOAT(OFS_RETURN+2) = 0;
560 Returns a number from 0<= num < 1
565 void PF_random (void)
569 num = (rand ()&0x7fff) / ((float)0x7fff);
571 G_FLOAT(OFS_RETURN) = num;
578 particle(origin, color, count)
581 void PF_particle (void)
587 org = G_VECTOR(OFS_PARM0);
588 dir = G_VECTOR(OFS_PARM1);
589 color = G_FLOAT(OFS_PARM2);
590 count = G_FLOAT(OFS_PARM3);
591 SV_StartParticle (org, dir, color, count);
601 void PF_ambientsound (void)
606 float vol, attenuation;
607 int i, soundnum, large;
609 pos = G_VECTOR (OFS_PARM0);
610 samp = G_STRING(OFS_PARM1);
611 vol = G_FLOAT(OFS_PARM2);
612 attenuation = G_FLOAT(OFS_PARM3);
614 // check to see if samp was properly precached
615 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
616 if (!strcmp(*check,samp))
621 Con_Printf ("no precache: %s\n", samp);
629 // add an svc_spawnambient command to the level signon packet
632 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
634 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
636 for (i=0 ; i<3 ; i++)
637 MSG_WriteDPCoord(&sv.signon, pos[i]);
640 MSG_WriteShort (&sv.signon, soundnum);
642 MSG_WriteByte (&sv.signon, soundnum);
644 MSG_WriteByte (&sv.signon, vol*255);
645 MSG_WriteByte (&sv.signon, attenuation*64);
653 Each entity can have eight independant sound sources, like voice,
656 Channel 0 is an auto-allocate channel, the others override anything
657 already running on that entity/channel pair.
659 An attenuation of 0 will play full volume everywhere in the level.
660 Larger attenuations will drop off.
672 entity = G_EDICT(OFS_PARM0);
673 channel = G_FLOAT(OFS_PARM1);
674 sample = G_STRING(OFS_PARM2);
675 volume = G_FLOAT(OFS_PARM3) * 255;
676 attenuation = G_FLOAT(OFS_PARM4);
678 if (volume < 0 || volume > 255)
679 Host_Error ("SV_StartSound: volume = %i", volume);
681 if (attenuation < 0 || attenuation > 4)
682 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
684 if (channel < 0 || channel > 7)
685 Host_Error ("SV_StartSound: channel = %i", channel);
687 SV_StartSound (entity, channel, sample, volume, attenuation);
699 Host_Error ("break statement");
706 Used for use tracing and shot targeting
707 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
708 if the tryents flag is set.
710 traceline (vector1, vector2, tryents)
713 void PF_traceline (void)
720 pr_xfunction->builtinsprofile += 30;
722 v1 = G_VECTOR(OFS_PARM0);
723 v2 = G_VECTOR(OFS_PARM1);
724 nomonsters = G_FLOAT(OFS_PARM2);
725 ent = G_EDICT(OFS_PARM3);
727 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
729 pr_global_struct->trace_allsolid = trace.allsolid;
730 pr_global_struct->trace_startsolid = trace.startsolid;
731 pr_global_struct->trace_fraction = trace.fraction;
732 pr_global_struct->trace_inwater = trace.inwater;
733 pr_global_struct->trace_inopen = trace.inopen;
734 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
735 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
736 pr_global_struct->trace_plane_dist = trace.plane.dist;
738 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
740 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
741 // FIXME: add trace_endcontents
749 Used for use tracing and shot targeting
750 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
751 if the tryents flag is set.
753 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
756 // LordHavoc: added this for my own use, VERY useful, similar to traceline
757 void PF_tracebox (void)
759 float *v1, *v2, *m1, *m2;
764 pr_xfunction->builtinsprofile += 30;
766 v1 = G_VECTOR(OFS_PARM0);
767 m1 = G_VECTOR(OFS_PARM1);
768 m2 = G_VECTOR(OFS_PARM2);
769 v2 = G_VECTOR(OFS_PARM3);
770 nomonsters = G_FLOAT(OFS_PARM4);
771 ent = G_EDICT(OFS_PARM5);
773 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
775 pr_global_struct->trace_allsolid = trace.allsolid;
776 pr_global_struct->trace_startsolid = trace.startsolid;
777 pr_global_struct->trace_fraction = trace.fraction;
778 pr_global_struct->trace_inwater = trace.inwater;
779 pr_global_struct->trace_inopen = trace.inopen;
780 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
781 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
782 pr_global_struct->trace_plane_dist = trace.plane.dist;
784 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
786 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
789 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
790 void PF_TraceToss (void)
796 pr_xfunction->builtinsprofile += 600;
798 ent = G_EDICT(OFS_PARM0);
799 ignore = G_EDICT(OFS_PARM1);
801 trace = SV_Trace_Toss (ent, ignore);
803 pr_global_struct->trace_allsolid = trace.allsolid;
804 pr_global_struct->trace_startsolid = trace.startsolid;
805 pr_global_struct->trace_fraction = trace.fraction;
806 pr_global_struct->trace_inwater = trace.inwater;
807 pr_global_struct->trace_inopen = trace.inopen;
808 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
809 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
810 pr_global_struct->trace_plane_dist = trace.plane.dist;
812 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
814 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
822 Returns true if the given entity can move to the given position from it's
823 current position by walking or rolling.
825 scalar checkpos (entity, vector)
828 void PF_checkpos (void)
832 //============================================================================
835 qbyte checkpvs[MAX_MAP_LEAFS/8];
837 int PF_newcheckclient (int check)
843 // cycle to the next one
845 check = bound(1, check, svs.maxclients);
846 if (check == svs.maxclients)
854 pr_xfunction->builtinsprofile++;
856 if (i == svs.maxclients+1)
858 // look up the client's edict
860 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
861 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
863 // found a valid client (possibly the same one again)
867 // get the PVS for the entity
868 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
870 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
871 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
880 Returns a client (or object that has a client enemy) that would be a
883 If there is more than one valid option, they are cycled each frame
885 If (self.origin + self.viewofs) is not in the PVS of the current target,
886 it is not returned at all.
891 int c_invis, c_notvis;
892 void PF_checkclient (void)
897 // find a new check if on a new frame
898 if (sv.time - sv.lastchecktime >= 0.1)
900 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
901 sv.lastchecktime = sv.time;
904 // return check if it might be visible
905 ent = EDICT_NUM(sv.lastcheck);
906 if (ent->e->free || ent->v->health <= 0)
908 RETURN_EDICT(sv.edicts);
912 // if current entity can't possibly see the check entity, return 0
913 self = PROG_TO_EDICT(pr_global_struct->self);
914 VectorAdd(self->v->origin, self->v->view_ofs, view);
915 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
918 RETURN_EDICT(sv.edicts);
922 // might be able to see it
927 //============================================================================
934 Sends text over to the client's execution buffer
936 stuffcmd (clientent, value)
939 void PF_stuffcmd (void)
945 entnum = G_EDICTNUM(OFS_PARM0);
946 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
948 Con_Printf("Can't stuffcmd to a non-client");
951 str = G_STRING(OFS_PARM1);
954 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
955 Host_ClientCommands ("%s", str);
963 Sends text over to the client's execution buffer
968 void PF_localcmd (void)
970 Cbuf_AddText(G_STRING(OFS_PARM0));
982 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
992 void PF_cvar_set (void)
994 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1001 Returns a chain of entities that have origins within a spherical area
1003 findradius (origin, radius)
1006 void PF_findradius (void)
1008 edict_t *ent, *chain;
1015 chain = (edict_t *)sv.edicts;
1017 org = G_VECTOR(OFS_PARM0);
1018 radius = G_FLOAT(OFS_PARM1);
1019 radius2 = radius * radius;
1021 ent = NEXT_EDICT(sv.edicts);
1022 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1024 pr_xfunction->builtinsprofile++;
1027 if (ent->v->solid == SOLID_NOT)
1030 // LordHavoc: compare against bounding box rather than center,
1031 // and use DotProduct instead of Length, major speedup
1032 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1033 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1034 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1035 if (DotProduct(eorg, eorg) > radius2)
1038 ent->v->chain = EDICT_TO_PROG(chain);
1042 RETURN_EDICT(chain);
1051 void PF_dprint (void)
1053 char string[STRINGTEMP_LENGTH];
1054 if (developer.integer)
1056 PF_VarString(0, string, sizeof(string));
1057 Con_Printf("%s",string);
1065 v = G_FLOAT(OFS_PARM0);
1067 s = PR_GetTempString();
1068 if ((float)((int)v) == v)
1069 sprintf(s, "%i", (int)v);
1071 sprintf(s, "%f", v);
1072 G_INT(OFS_RETURN) = PR_SetString(s);
1078 v = G_FLOAT(OFS_PARM0);
1079 G_FLOAT(OFS_RETURN) = fabs(v);
1085 s = PR_GetTempString();
1086 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1087 G_INT(OFS_RETURN) = PR_SetString(s);
1093 s = PR_GetTempString();
1094 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1095 G_INT(OFS_RETURN) = PR_SetString(s);
1098 void PF_Spawn (void)
1101 pr_xfunction->builtinsprofile += 20;
1106 void PF_Remove (void)
1109 pr_xfunction->builtinsprofile += 20;
1111 ed = G_EDICT(OFS_PARM0);
1112 if (ed == sv.edicts)
1113 Host_Error("remove: tried to remove world\n");
1114 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1115 Host_Error("remove: tried to remove a client\n");
1120 // entity (entity start, .string field, string match) find = #5;
1128 e = G_EDICTNUM(OFS_PARM0);
1129 f = G_INT(OFS_PARM1);
1130 s = G_STRING(OFS_PARM2);
1133 RETURN_EDICT(sv.edicts);
1137 for (e++ ; e < sv.num_edicts ; e++)
1139 pr_xfunction->builtinsprofile++;
1153 RETURN_EDICT(sv.edicts);
1156 // LordHavoc: added this for searching float, int, and entity reference fields
1157 void PF_FindFloat (void)
1164 e = G_EDICTNUM(OFS_PARM0);
1165 f = G_INT(OFS_PARM1);
1166 s = G_FLOAT(OFS_PARM2);
1168 for (e++ ; e < sv.num_edicts ; e++)
1170 pr_xfunction->builtinsprofile++;
1174 if (E_FLOAT(ed,f) == s)
1181 RETURN_EDICT(sv.edicts);
1184 // chained search for strings in entity fields
1185 // entity(.string field, string match) findchain = #402;
1186 void PF_findchain (void)
1191 edict_t *ent, *chain;
1193 chain = (edict_t *)sv.edicts;
1195 f = G_INT(OFS_PARM0);
1196 s = G_STRING(OFS_PARM1);
1199 RETURN_EDICT(sv.edicts);
1203 ent = NEXT_EDICT(sv.edicts);
1204 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1206 pr_xfunction->builtinsprofile++;
1209 t = E_STRING(ent,f);
1215 ent->v->chain = EDICT_TO_PROG(chain);
1219 RETURN_EDICT(chain);
1222 // LordHavoc: chained search for float, int, and entity reference fields
1223 // entity(.string field, float match) findchainfloat = #403;
1224 void PF_findchainfloat (void)
1229 edict_t *ent, *chain;
1231 chain = (edict_t *)sv.edicts;
1233 f = G_INT(OFS_PARM0);
1234 s = G_FLOAT(OFS_PARM1);
1236 ent = NEXT_EDICT(sv.edicts);
1237 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1239 pr_xfunction->builtinsprofile++;
1242 if (E_FLOAT(ent,f) != s)
1245 ent->v->chain = EDICT_TO_PROG(chain);
1249 RETURN_EDICT(chain);
1252 void PR_CheckEmptyString (char *s)
1255 Host_Error ("Bad string");
1258 void PF_precache_file (void)
1259 { // precache_file is only used to copy files with qcc, it does nothing
1260 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1263 void PF_precache_sound (void)
1268 if (sv.state != ss_loading)
1269 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1271 s = G_STRING(OFS_PARM0);
1272 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1273 PR_CheckEmptyString (s);
1275 for (i=0 ; i<MAX_SOUNDS ; i++)
1277 if (!sv.sound_precache[i])
1279 sv.sound_precache[i] = s;
1282 if (!strcmp(sv.sound_precache[i], s))
1285 Host_Error ("PF_precache_sound: overflow");
1288 void PF_precache_model (void)
1293 if (sv.state != ss_loading)
1294 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1296 s = G_STRING(OFS_PARM0);
1297 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1299 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1300 PR_CheckEmptyString (s);
1302 for (i=0 ; i<MAX_MODELS ; i++)
1304 if (!sv.model_precache[i])
1306 sv.model_precache[i] = s;
1307 sv.models[i] = Mod_ForName (s, true, false, false);
1310 if (!strcmp(sv.model_precache[i], s))
1313 Host_Error ("PF_precache_model: overflow");
1317 void PF_coredump (void)
1322 void PF_traceon (void)
1327 void PF_traceoff (void)
1332 void PF_eprint (void)
1334 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1341 float(float yaw, float dist) walkmove
1344 void PF_walkmove (void)
1352 ent = PROG_TO_EDICT(pr_global_struct->self);
1353 yaw = G_FLOAT(OFS_PARM0);
1354 dist = G_FLOAT(OFS_PARM1);
1356 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1358 G_FLOAT(OFS_RETURN) = 0;
1362 yaw = yaw*M_PI*2 / 360;
1364 move[0] = cos(yaw)*dist;
1365 move[1] = sin(yaw)*dist;
1368 // save program state, because SV_movestep may call other progs
1369 oldf = pr_xfunction;
1370 oldself = pr_global_struct->self;
1372 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1375 // restore program state
1376 pr_xfunction = oldf;
1377 pr_global_struct->self = oldself;
1387 void PF_droptofloor (void)
1393 ent = PROG_TO_EDICT(pr_global_struct->self);
1395 VectorCopy (ent->v->origin, end);
1398 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1400 if (trace.fraction == 1)
1401 G_FLOAT(OFS_RETURN) = 0;
1404 VectorCopy (trace.endpos, ent->v->origin);
1405 SV_LinkEdict (ent, false);
1406 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1407 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1408 G_FLOAT(OFS_RETURN) = 1;
1409 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1410 ent->e->suspendedinairflag = true;
1418 void(float style, string value) lightstyle
1421 void PF_lightstyle (void)
1428 style = G_FLOAT(OFS_PARM0);
1429 val = G_STRING(OFS_PARM1);
1431 // change the string in sv
1432 sv.lightstyles[style] = val;
1434 // send message to all clients on this server
1435 if (sv.state != ss_active)
1438 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1440 if (client->netconnection)
1442 MSG_WriteChar (&client->message, svc_lightstyle);
1443 MSG_WriteChar (&client->message,style);
1444 MSG_WriteString (&client->message, val);
1452 f = G_FLOAT(OFS_PARM0);
1454 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1456 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1458 void PF_floor (void)
1460 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1464 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1473 void PF_checkbottom (void)
1475 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1483 void PF_pointcontents (void)
1485 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1492 entity nextent(entity)
1495 void PF_nextent (void)
1500 i = G_EDICTNUM(OFS_PARM0);
1503 pr_xfunction->builtinsprofile++;
1505 if (i == sv.num_edicts)
1507 RETURN_EDICT(sv.edicts);
1523 Pick a vector for the player to shoot along
1524 vector aim(entity, missilespeed)
1529 edict_t *ent, *check, *bestent;
1530 vec3_t start, dir, end, bestdir;
1533 float dist, bestdist;
1536 ent = G_EDICT(OFS_PARM0);
1537 speed = G_FLOAT(OFS_PARM1);
1539 VectorCopy (ent->v->origin, start);
1542 // try sending a trace straight
1543 VectorCopy (pr_global_struct->v_forward, dir);
1544 VectorMA (start, 2048, dir, end);
1545 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1546 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1547 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1549 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1554 // try all possible entities
1555 VectorCopy (dir, bestdir);
1556 bestdist = sv_aim.value;
1559 check = NEXT_EDICT(sv.edicts);
1560 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1562 pr_xfunction->builtinsprofile++;
1563 if (check->v->takedamage != DAMAGE_AIM)
1567 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1568 continue; // don't aim at teammate
1569 for (j=0 ; j<3 ; j++)
1570 end[j] = check->v->origin[j]
1571 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1572 VectorSubtract (end, start, dir);
1573 VectorNormalize (dir);
1574 dist = DotProduct (dir, pr_global_struct->v_forward);
1575 if (dist < bestdist)
1576 continue; // to far to turn
1577 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1578 if (tr.ent == check)
1579 { // can shoot at this one
1587 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1588 dist = DotProduct (dir, pr_global_struct->v_forward);
1589 VectorScale (pr_global_struct->v_forward, dist, end);
1591 VectorNormalize (end);
1592 VectorCopy (end, G_VECTOR(OFS_RETURN));
1596 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1604 This was a major timewaster in progs, so it was converted to C
1607 void PF_changeyaw (void)
1610 float ideal, current, move, speed;
1612 ent = PROG_TO_EDICT(pr_global_struct->self);
1613 current = ANGLEMOD(ent->v->angles[1]);
1614 ideal = ent->v->ideal_yaw;
1615 speed = ent->v->yaw_speed;
1617 if (current == ideal)
1619 move = ideal - current;
1620 if (ideal > current)
1641 ent->v->angles[1] = ANGLEMOD (current + move);
1649 void PF_changepitch (void)
1652 float ideal, current, move, speed;
1655 ent = G_EDICT(OFS_PARM0);
1656 current = ANGLEMOD( ent->v->angles[0] );
1657 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1658 ideal = val->_float;
1661 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1664 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1665 speed = val->_float;
1668 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1672 if (current == ideal)
1674 move = ideal - current;
1675 if (ideal > current)
1696 ent->v->angles[0] = ANGLEMOD (current + move);
1700 ===============================================================================
1704 ===============================================================================
1707 #define MSG_BROADCAST 0 // unreliable to all
1708 #define MSG_ONE 1 // reliable to one (msg_entity)
1709 #define MSG_ALL 2 // reliable to all
1710 #define MSG_INIT 3 // write to the init string
1712 sizebuf_t *WriteDest (void)
1718 dest = G_FLOAT(OFS_PARM0);
1722 return &sv.datagram;
1725 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1726 entnum = NUM_FOR_EDICT(ent);
1727 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1728 Con_Printf("WriteDest: tried to write to non-client\n");
1729 return &svs.clients[entnum-1].message;
1732 return &sv.reliable_datagram;
1738 Host_Error ("WriteDest: bad destination");
1745 void PF_WriteByte (void)
1747 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1750 void PF_WriteChar (void)
1752 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1755 void PF_WriteShort (void)
1757 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1760 void PF_WriteLong (void)
1762 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1765 void PF_WriteAngle (void)
1767 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1770 void PF_WriteCoord (void)
1772 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1775 void PF_WriteString (void)
1777 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1781 void PF_WriteEntity (void)
1783 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1786 //=============================================================================
1788 void PF_makestatic (void)
1793 ent = G_EDICT(OFS_PARM0);
1796 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1801 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1802 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1803 MSG_WriteShort (&sv.signon, ent->v->frame);
1807 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1808 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1809 MSG_WriteByte (&sv.signon, ent->v->frame);
1812 MSG_WriteByte (&sv.signon, ent->v->colormap);
1813 MSG_WriteByte (&sv.signon, ent->v->skin);
1814 for (i=0 ; i<3 ; i++)
1816 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1817 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1820 // throw the entity away now
1824 //=============================================================================
1831 void PF_setspawnparms (void)
1837 ent = G_EDICT(OFS_PARM0);
1838 i = NUM_FOR_EDICT(ent);
1839 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1841 Con_Printf("tried to setspawnparms on a non-client\n");
1845 // copy spawn parms out of the client_t
1846 client = svs.clients + 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 > svs.maxclients || !svs.clients[entnum-1].active)
2087 Con_Printf ("tried to setcolor a non-client\n");
2091 client = svs.clients + entnum-1;
2092 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2095 client->old_colors = i;
2096 client->edict->v->team = (i & 15) + 1;
2098 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2099 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2100 MSG_WriteByte (&sv.reliable_datagram, i);
2107 effect(origin, modelname, startframe, framecount, framerate)
2110 void PF_effect (void)
2113 s = G_STRING(OFS_PARM1);
2115 Host_Error("effect: no model specified\n");
2117 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2120 void PF_te_blood (void)
2122 if (G_FLOAT(OFS_PARM2) < 1)
2124 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2125 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2127 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2128 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2129 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2131 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2132 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2133 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2135 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2138 void PF_te_bloodshower (void)
2140 if (G_FLOAT(OFS_PARM3) < 1)
2142 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2143 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2145 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2146 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2147 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2149 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2150 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2151 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2153 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2155 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2158 void PF_te_explosionrgb (void)
2160 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2161 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2163 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2164 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2165 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2167 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2168 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2169 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2172 void PF_te_particlecube (void)
2174 if (G_FLOAT(OFS_PARM3) < 1)
2176 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2177 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2179 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2180 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2181 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2184 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2185 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2189 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2191 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2193 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2194 // gravity true/false
2195 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2197 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2200 void PF_te_particlerain (void)
2202 if (G_FLOAT(OFS_PARM3) < 1)
2204 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2205 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2207 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2208 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2209 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2213 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2217 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2219 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2221 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2224 void PF_te_particlesnow (void)
2226 if (G_FLOAT(OFS_PARM3) < 1)
2228 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2229 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2231 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2232 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2237 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2241 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2243 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2245 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2248 void PF_te_spark (void)
2250 if (G_FLOAT(OFS_PARM2) < 1)
2252 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2253 MSG_WriteByte(&sv.datagram, TE_SPARK);
2255 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2256 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2257 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2259 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2260 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2261 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2263 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2266 void PF_te_gunshotquad (void)
2268 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2269 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2271 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2272 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2273 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2276 void PF_te_spikequad (void)
2278 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2279 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2286 void PF_te_superspikequad (void)
2288 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2289 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2292 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2293 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2296 void PF_te_explosionquad (void)
2298 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2299 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2301 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2302 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2303 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2306 void PF_te_smallflash (void)
2308 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2309 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2312 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2313 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2316 void PF_te_customflash (void)
2318 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2320 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2321 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2323 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2324 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2325 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2327 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2329 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2331 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2332 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2333 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2336 void PF_te_gunshot (void)
2338 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2339 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2341 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2342 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2343 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2346 void PF_te_spike (void)
2348 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2349 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2353 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2356 void PF_te_superspike (void)
2358 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2359 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2363 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2366 void PF_te_explosion (void)
2368 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2369 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2376 void PF_te_tarexplosion (void)
2378 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2379 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2381 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2382 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2383 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2386 void PF_te_wizspike (void)
2388 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2389 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2392 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2393 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2396 void PF_te_knightspike (void)
2398 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2399 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2402 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2403 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2406 void PF_te_lavasplash (void)
2408 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2409 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2413 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2416 void PF_te_teleport (void)
2418 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2419 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2423 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2426 void PF_te_explosion2 (void)
2428 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2429 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2433 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2435 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2438 void PF_te_lightning1 (void)
2440 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2441 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2443 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2445 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2446 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2447 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2451 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2454 void PF_te_lightning2 (void)
2456 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2457 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2459 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2465 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2466 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2467 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2470 void PF_te_lightning3 (void)
2472 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2473 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2475 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2477 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2478 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2479 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2483 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2486 void PF_te_beam (void)
2488 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2489 MSG_WriteByte(&sv.datagram, TE_BEAM);
2491 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2499 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2502 void PF_te_plasmaburn (void)
2504 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2505 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2508 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2511 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2514 vec3_t v1, clipplanenormal, normal;
2515 vec_t clipplanedist, clipdist;
2517 if (surf->flags & SURF_PLANEBACK)
2518 VectorNegate(surf->plane->normal, normal);
2520 VectorCopy(surf->plane->normal, normal);
2521 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2523 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2524 VectorNormalizeFast(v1);
2525 CrossProduct(v1, normal, clipplanenormal);
2526 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2527 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2530 clipdist = -clipdist;
2531 VectorMA(out, clipdist, clipplanenormal, out);
2536 static msurface_t *getsurface(edict_t *ed, int surfnum)
2540 if (!ed || ed->e->free)
2542 modelindex = ed->v->modelindex;
2543 if (modelindex < 1 || modelindex >= MAX_MODELS)
2545 model = sv.models[modelindex];
2546 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2548 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2552 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2553 void PF_getsurfacenumpoints(void)
2556 // return 0 if no such surface
2557 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2559 G_FLOAT(OFS_RETURN) = 0;
2563 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2565 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2566 void PF_getsurfacepoint(void)
2571 VectorClear(G_VECTOR(OFS_RETURN));
2572 ed = G_EDICT(OFS_PARM0);
2573 if (!ed || ed->e->free)
2575 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2577 pointnum = G_FLOAT(OFS_PARM2);
2578 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2580 // FIXME: implement rotation/scaling
2581 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2583 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2584 void PF_getsurfacenormal(void)
2587 VectorClear(G_VECTOR(OFS_RETURN));
2588 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2590 // FIXME: implement rotation/scaling
2591 if (surf->flags & SURF_PLANEBACK)
2592 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2594 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2596 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2597 void PF_getsurfacetexture(void)
2600 G_INT(OFS_RETURN) = 0;
2601 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2603 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2605 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2606 void PF_getsurfacenearpoint(void)
2608 int surfnum, best, modelindex;
2610 vec_t dist, bestdist;
2615 G_FLOAT(OFS_RETURN) = -1;
2616 ed = G_EDICT(OFS_PARM0);
2617 point = G_VECTOR(OFS_PARM1);
2619 if (!ed || ed->e->free)
2621 modelindex = ed->v->modelindex;
2622 if (modelindex < 1 || modelindex >= MAX_MODELS)
2624 model = sv.models[modelindex];
2625 if (!model->brushq1.numsurfaces)
2628 // FIXME: implement rotation/scaling
2629 VectorSubtract(point, ed->v->origin, p);
2631 bestdist = 1000000000;
2632 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2634 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2635 dist = PlaneDiff(p, surf->plane);
2637 if (dist < bestdist)
2639 clippointtosurface(surf, p, clipped);
2640 VectorSubtract(clipped, p, clipped);
2641 dist += DotProduct(clipped, clipped);
2642 if (dist < bestdist)
2649 G_FLOAT(OFS_RETURN) = best;
2651 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2652 void PF_getsurfaceclippedpoint(void)
2657 VectorClear(G_VECTOR(OFS_RETURN));
2658 ed = G_EDICT(OFS_PARM0);
2659 if (!ed || ed->e->free)
2661 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2663 // FIXME: implement rotation/scaling
2664 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2665 clippointtosurface(surf, p, out);
2666 // FIXME: implement rotation/scaling
2667 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2670 #define MAX_PRFILES 256
2672 qfile_t *pr_files[MAX_PRFILES];
2674 void PR_Files_Init(void)
2676 memset(pr_files, 0, sizeof(pr_files));
2679 void PR_Files_CloseAll(void)
2682 for (i = 0;i < MAX_PRFILES;i++)
2685 FS_Close(pr_files[i]);
2690 //float(string s) stof = #81; // get numerical value from a string
2693 char string[STRINGTEMP_LENGTH];
2694 PF_VarString(0, string, sizeof(string));
2695 G_FLOAT(OFS_RETURN) = atof(string);
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[STRINGTEMP_LENGTH];
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 < STRINGTEMP_LENGTH - 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 string[STRINGTEMP_LENGTH];
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 PF_VarString(1, string, sizeof(string));
2819 if ((stringlength = strlen(string)))
2820 FS_Write(pr_files[filenum], string, stringlength);
2821 if (developer.integer)
2822 Con_Printf("fputs: %s\n", string);
2825 //float(string s) strlen = #114; // returns how many characters are in a string
2826 void PF_strlen(void)
2829 s = G_STRING(OFS_PARM0);
2831 G_FLOAT(OFS_RETURN) = strlen(s);
2833 G_FLOAT(OFS_RETURN) = 0;
2836 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2837 void PF_strcat(void)
2839 char *s = PR_GetTempString();
2840 PF_VarString(0, s, STRINGTEMP_LENGTH);
2841 G_INT(OFS_RETURN) = PR_SetString(s);
2844 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2845 void PF_substring(void)
2847 int i, start, length;
2848 char *s, *string = PR_GetTempString();
2849 s = G_STRING(OFS_PARM0);
2850 start = G_FLOAT(OFS_PARM1);
2851 length = G_FLOAT(OFS_PARM2);
2854 for (i = 0;i < start && *s;i++, s++);
2855 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2858 G_INT(OFS_RETURN) = PR_SetString(string);
2861 //vector(string s) stov = #117; // returns vector value from a string
2864 char string[STRINGTEMP_LENGTH];
2865 PF_VarString(0, string, sizeof(string));
2866 Math_atov(string, G_VECTOR(OFS_RETURN));
2869 //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
2870 void PF_strzone(void)
2873 in = G_STRING(OFS_PARM0);
2874 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2876 G_INT(OFS_RETURN) = PR_SetString(out);
2879 //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
2880 void PF_strunzone(void)
2882 Mem_Free(G_STRING(OFS_PARM0));
2885 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2886 //this function originally written by KrimZon, made shorter by LordHavoc
2887 void PF_clientcommand (void)
2889 client_t *temp_client;
2892 //find client for this entity
2893 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2894 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2896 Con_Printf("PF_clientcommand: entity is not a client");
2900 temp_client = host_client;
2901 host_client = svs.clients + i;
2902 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2903 host_client = temp_client;
2906 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2907 //this function originally written by KrimZon, made shorter by LordHavoc
2908 char **tokens = NULL;
2909 int max_tokens, num_tokens = 0;
2910 void PF_tokenize (void)
2914 str = G_STRING(OFS_PARM0);
2919 for (i=0;i<num_tokens;i++)
2925 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2926 max_tokens = strlen(str);
2928 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2930 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2931 strcpy(tokens[num_tokens], com_token);
2934 G_FLOAT(OFS_RETURN) = num_tokens;
2937 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2938 //this function originally written by KrimZon, made shorter by LordHavoc
2941 int token_num = G_FLOAT(OFS_PARM0);
2942 if (token_num >= 0 && token_num < num_tokens)
2943 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2945 G_INT(OFS_RETURN) = PR_SetString("");
2948 //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)
2949 void PF_setattachment (void)
2951 edict_t *e = G_EDICT(OFS_PARM0);
2952 edict_t *tagentity = G_EDICT(OFS_PARM1);
2953 char *tagname = G_STRING(OFS_PARM2);
2958 if (tagentity == NULL)
2959 tagentity = sv.edicts;
2961 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2963 v->edict = EDICT_TO_PROG(tagentity);
2965 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2968 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2970 modelindex = (int)tagentity->v->modelindex;
2971 if (modelindex >= 0 && modelindex < MAX_MODELS)
2973 model = sv.models[modelindex];
2974 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2975 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2976 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2978 if (v->_float == 0 && model->alias.aliasnum_tags)
2979 for (i = 0;i < model->alias.aliasnum_tags;i++)
2980 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2983 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);
2986 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));
2991 builtin_t pr_builtin[] =
2994 PF_makevectors, // #1 void(entity e) makevectors
2995 PF_setorigin, // #2 void(entity e, vector o) setorigin
2996 PF_setmodel, // #3 void(entity e, string m) setmodel
2997 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2998 NULL, // #5 void(entity e, vector min, vector max) setabssize
2999 PF_break, // #6 void() break
3000 PF_random, // #7 float() random
3001 PF_sound, // #8 void(entity e, float chan, string samp) sound
3002 PF_normalize, // #9 vector(vector v) normalize
3003 PF_error, // #10 void(string e) error
3004 PF_objerror, // #11 void(string e) objerror
3005 PF_vlen, // #12 float(vector v) vlen
3006 PF_vectoyaw, // #13 float(vector v) vectoyaw
3007 PF_Spawn, // #14 entity() spawn
3008 PF_Remove, // #15 void(entity e) remove
3009 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3010 PF_checkclient, // #17 entity() clientlist
3011 PF_Find, // #18 entity(entity start, .string fld, string match) find
3012 PF_precache_sound, // #19 void(string s) precache_sound
3013 PF_precache_model, // #20 void(string s) precache_model
3014 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3015 PF_findradius, // #22 entity(vector org, float rad) findradius
3016 PF_bprint, // #23 void(string s) bprint
3017 PF_sprint, // #24 void(entity client, string s) sprint
3018 PF_dprint, // #25 void(string s) dprint
3019 PF_ftos, // #26 void(string s) ftos
3020 PF_vtos, // #27 void(string s) vtos
3021 PF_coredump, // #28 void() coredump
3022 PF_traceon, // #29 void() traceon
3023 PF_traceoff, // #30 void() traceoff
3024 PF_eprint, // #31 void(entity e) eprint
3025 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3027 PF_droptofloor, // #34 float() droptofloor
3028 PF_lightstyle, // #35 void(float style, string value) lightstyle
3029 PF_rint, // #36 float(float v) rint
3030 PF_floor, // #37 float(float v) floor
3031 PF_ceil, // #38 float(float v) ceil
3033 PF_checkbottom, // #40 float(entity e) checkbottom
3034 PF_pointcontents , // #41 float(vector v) pointcontents
3036 PF_fabs, // #43 float(float f) fabs
3037 PF_aim, // #44 vector(entity e, float speed) aim
3038 PF_cvar, // #45 float(string s) cvar
3039 PF_localcmd, // #46 void(string s) localcmd
3040 PF_nextent, // #47 entity(entity e) nextent
3041 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3042 PF_changeyaw, // #49 void() ChangeYaw
3044 PF_vectoangles, // #51 vector(vector v) vectoangles
3045 PF_WriteByte, // #52 void(float to, float f) WriteByte
3046 PF_WriteChar, // #53 void(float to, float f) WriteChar
3047 PF_WriteShort, // #54 void(float to, float f) WriteShort
3048 PF_WriteLong, // #55 void(float to, float f) WriteLong
3049 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3050 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3051 PF_WriteString, // #58 void(float to, string s) WriteString
3052 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3053 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3054 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3055 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3056 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3057 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3058 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3060 SV_MoveToGoal, // #67 void(float step) movetogoal
3061 PF_precache_file, // #68 string(string s) precache_file
3062 PF_makestatic, // #69 void(entity e) makestatic
3063 PF_changelevel, // #70 void(string s) changelevel
3065 PF_cvar_set, // #72 void(string var, string val) cvar_set
3066 PF_centerprint, // #73 void(entity client, strings) centerprint
3067 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3068 PF_precache_model, // #75 string(string s) precache_model2
3069 PF_precache_sound, // #76 string(string s) precache_sound2
3070 PF_precache_file, // #77 string(string s) precache_file2
3071 PF_setspawnparms, // #78 void(entity e) setspawnparms
3074 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3083 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3084 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3085 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3086 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3087 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3088 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3089 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3090 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3091 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3092 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3103 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3104 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3105 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3106 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3107 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3108 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3109 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3110 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3111 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3112 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3113 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3114 a a a a a a a a // #120-199
3115 a a a a a a a a a a // #200-299
3116 a a a a a a a a a a // #300-399
3117 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3118 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3119 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3120 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3121 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3122 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3123 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3124 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3125 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3126 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3127 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3128 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3129 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3130 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3131 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3132 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3133 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3134 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3135 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3136 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3137 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3138 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3139 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3140 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3141 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3142 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3143 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3144 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3145 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3146 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3147 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3148 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3149 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3150 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3151 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3152 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3153 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3154 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3155 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3156 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3157 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3158 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3159 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3160 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3167 a a a a a // #450-499 (LordHavoc)
3170 builtin_t *pr_builtins = pr_builtin;
3171 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3173 void PR_Cmd_Init(void)
3175 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3179 void PR_Cmd_Reset(void)
3181 Mem_EmptyPool(pr_strings_mempool);
3182 PR_Files_CloseAll();