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 > svs.maxclients || !svs.clients[entnum-1].active)
377 Con_Printf ("tried to sprint to a non-client\n");
381 client = svs.clients + entnum-1;
382 if (!client->netconnection)
384 MSG_WriteChar(&client->message,svc_print);
385 MSG_WriteString(&client->message, s );
393 single print to a specific client
395 centerprint(clientent, value)
398 void PF_centerprint (void)
404 entnum = G_EDICTNUM(OFS_PARM0);
407 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
409 Con_Printf ("tried to sprint to a non-client\n");
413 client = svs.clients + entnum-1;
414 if (!client->netconnection)
416 MSG_WriteChar(&client->message,svc_centerprint);
417 MSG_WriteString(&client->message, s );
425 vector normalize(vector)
428 void PF_normalize (void)
434 value1 = G_VECTOR(OFS_PARM0);
436 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
440 newvalue[0] = newvalue[1] = newvalue[2] = 0;
444 newvalue[0] = value1[0] * new;
445 newvalue[1] = value1[1] * new;
446 newvalue[2] = value1[2] * new;
449 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
464 value1 = G_VECTOR(OFS_PARM0);
466 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
469 G_FLOAT(OFS_RETURN) = new;
476 float vectoyaw(vector)
479 void PF_vectoyaw (void)
484 value1 = G_VECTOR(OFS_PARM0);
486 if (value1[1] == 0 && value1[0] == 0)
490 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
495 G_FLOAT(OFS_RETURN) = yaw;
503 vector vectoangles(vector)
506 void PF_vectoangles (void)
512 value1 = G_VECTOR(OFS_PARM0);
514 if (value1[1] == 0 && value1[0] == 0)
524 // LordHavoc: optimized a bit
527 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
531 else if (value1[1] > 0)
536 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
537 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
542 G_FLOAT(OFS_RETURN+0) = pitch;
543 G_FLOAT(OFS_RETURN+1) = yaw;
544 G_FLOAT(OFS_RETURN+2) = 0;
551 Returns a number from 0<= num < 1
556 void PF_random (void)
560 num = (rand ()&0x7fff) / ((float)0x7fff);
562 G_FLOAT(OFS_RETURN) = num;
569 particle(origin, color, count)
572 void PF_particle (void)
578 org = G_VECTOR(OFS_PARM0);
579 dir = G_VECTOR(OFS_PARM1);
580 color = G_FLOAT(OFS_PARM2);
581 count = G_FLOAT(OFS_PARM3);
582 SV_StartParticle (org, dir, color, count);
592 void PF_ambientsound (void)
597 float vol, attenuation;
598 int i, soundnum, large;
600 pos = G_VECTOR (OFS_PARM0);
601 samp = G_STRING(OFS_PARM1);
602 vol = G_FLOAT(OFS_PARM2);
603 attenuation = G_FLOAT(OFS_PARM3);
605 // check to see if samp was properly precached
606 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
607 if (!strcmp(*check,samp))
612 Con_Printf ("no precache: %s\n", samp);
620 // add an svc_spawnambient command to the level signon packet
623 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
625 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
627 for (i=0 ; i<3 ; i++)
628 MSG_WriteDPCoord(&sv.signon, pos[i]);
631 MSG_WriteShort (&sv.signon, soundnum);
633 MSG_WriteByte (&sv.signon, soundnum);
635 MSG_WriteByte (&sv.signon, vol*255);
636 MSG_WriteByte (&sv.signon, attenuation*64);
644 Each entity can have eight independant sound sources, like voice,
647 Channel 0 is an auto-allocate channel, the others override anything
648 already running on that entity/channel pair.
650 An attenuation of 0 will play full volume everywhere in the level.
651 Larger attenuations will drop off.
663 entity = G_EDICT(OFS_PARM0);
664 channel = G_FLOAT(OFS_PARM1);
665 sample = G_STRING(OFS_PARM2);
666 volume = G_FLOAT(OFS_PARM3) * 255;
667 attenuation = G_FLOAT(OFS_PARM4);
669 if (volume < 0 || volume > 255)
670 Host_Error ("SV_StartSound: volume = %i", volume);
672 if (attenuation < 0 || attenuation > 4)
673 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
675 if (channel < 0 || channel > 7)
676 Host_Error ("SV_StartSound: channel = %i", channel);
678 SV_StartSound (entity, channel, sample, volume, attenuation);
690 Host_Error ("break statement");
697 Used for use tracing and shot targeting
698 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
699 if the tryents flag is set.
701 traceline (vector1, vector2, tryents)
704 void PF_traceline (void)
711 pr_xfunction->builtinsprofile += 30;
713 v1 = G_VECTOR(OFS_PARM0);
714 v2 = G_VECTOR(OFS_PARM1);
715 nomonsters = G_FLOAT(OFS_PARM2);
716 ent = G_EDICT(OFS_PARM3);
718 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
720 pr_global_struct->trace_allsolid = trace.allsolid;
721 pr_global_struct->trace_startsolid = trace.startsolid;
722 pr_global_struct->trace_fraction = trace.fraction;
723 pr_global_struct->trace_inwater = trace.inwater;
724 pr_global_struct->trace_inopen = trace.inopen;
725 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
726 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
727 pr_global_struct->trace_plane_dist = trace.plane.dist;
729 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
731 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
732 // FIXME: add trace_endcontents
740 Used for use tracing and shot targeting
741 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
742 if the tryents flag is set.
744 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
747 // LordHavoc: added this for my own use, VERY useful, similar to traceline
748 void PF_tracebox (void)
750 float *v1, *v2, *m1, *m2;
755 pr_xfunction->builtinsprofile += 30;
757 v1 = G_VECTOR(OFS_PARM0);
758 m1 = G_VECTOR(OFS_PARM1);
759 m2 = G_VECTOR(OFS_PARM2);
760 v2 = G_VECTOR(OFS_PARM3);
761 nomonsters = G_FLOAT(OFS_PARM4);
762 ent = G_EDICT(OFS_PARM5);
764 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
766 pr_global_struct->trace_allsolid = trace.allsolid;
767 pr_global_struct->trace_startsolid = trace.startsolid;
768 pr_global_struct->trace_fraction = trace.fraction;
769 pr_global_struct->trace_inwater = trace.inwater;
770 pr_global_struct->trace_inopen = trace.inopen;
771 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
772 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
773 pr_global_struct->trace_plane_dist = trace.plane.dist;
775 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
777 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
780 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
781 void PF_TraceToss (void)
787 pr_xfunction->builtinsprofile += 600;
789 ent = G_EDICT(OFS_PARM0);
790 ignore = G_EDICT(OFS_PARM1);
792 trace = SV_Trace_Toss (ent, ignore);
794 pr_global_struct->trace_allsolid = trace.allsolid;
795 pr_global_struct->trace_startsolid = trace.startsolid;
796 pr_global_struct->trace_fraction = trace.fraction;
797 pr_global_struct->trace_inwater = trace.inwater;
798 pr_global_struct->trace_inopen = trace.inopen;
799 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
800 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
801 pr_global_struct->trace_plane_dist = trace.plane.dist;
803 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
805 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
813 Returns true if the given entity can move to the given position from it's
814 current position by walking or rolling.
816 scalar checkpos (entity, vector)
819 void PF_checkpos (void)
823 //============================================================================
826 qbyte checkpvs[MAX_MAP_LEAFS/8];
828 int PF_newcheckclient (int check)
834 // cycle to the next one
836 check = bound(1, check, svs.maxclients);
837 if (check == svs.maxclients)
845 pr_xfunction->builtinsprofile++;
847 if (i == svs.maxclients+1)
849 // look up the client's edict
851 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
852 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
854 // found a valid client (possibly the same one again)
858 // get the PVS for the entity
859 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
861 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
862 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
871 Returns a client (or object that has a client enemy) that would be a
874 If there is more than one valid option, they are cycled each frame
876 If (self.origin + self.viewofs) is not in the PVS of the current target,
877 it is not returned at all.
882 int c_invis, c_notvis;
883 void PF_checkclient (void)
888 // find a new check if on a new frame
889 if (sv.time - sv.lastchecktime >= 0.1)
891 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
892 sv.lastchecktime = sv.time;
895 // return check if it might be visible
896 ent = EDICT_NUM(sv.lastcheck);
897 if (ent->e->free || ent->v->health <= 0)
899 RETURN_EDICT(sv.edicts);
903 // if current entity can't possibly see the check entity, return 0
904 self = PROG_TO_EDICT(pr_global_struct->self);
905 VectorAdd(self->v->origin, self->v->view_ofs, view);
906 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
909 RETURN_EDICT(sv.edicts);
913 // might be able to see it
918 //============================================================================
925 Sends text over to the client's execution buffer
927 stuffcmd (clientent, value)
930 void PF_stuffcmd (void)
936 entnum = G_EDICTNUM(OFS_PARM0);
937 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
939 Con_Printf("Can't stuffcmd to a non-client");
942 str = G_STRING(OFS_PARM1);
945 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
946 Host_ClientCommands ("%s", str);
954 Sends text over to the client's execution buffer
959 void PF_localcmd (void)
961 Cbuf_AddText(G_STRING(OFS_PARM0));
973 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
983 void PF_cvar_set (void)
985 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
992 Returns a chain of entities that have origins within a spherical area
994 findradius (origin, radius)
997 void PF_findradius (void)
999 edict_t *ent, *chain;
1006 chain = (edict_t *)sv.edicts;
1008 org = G_VECTOR(OFS_PARM0);
1009 radius = G_FLOAT(OFS_PARM1);
1010 radius2 = radius * radius;
1012 ent = NEXT_EDICT(sv.edicts);
1013 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1015 pr_xfunction->builtinsprofile++;
1018 if (ent->v->solid == SOLID_NOT)
1021 // LordHavoc: compare against bounding box rather than center,
1022 // and use DotProduct instead of Length, major speedup
1023 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1024 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1025 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1026 if (DotProduct(eorg, eorg) > radius2)
1029 ent->v->chain = EDICT_TO_PROG(chain);
1033 RETURN_EDICT(chain);
1042 void PF_dprint (void)
1044 Con_DPrintf ("%s",PF_VarString(0));
1047 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1048 #define STRINGTEMP_BUFFERS 16
1049 #define STRINGTEMP_LENGTH 128
1050 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1051 static int pr_string_tempindex = 0;
1053 static char *PR_GetTempString(void)
1056 s = pr_string_temp[pr_string_tempindex];
1057 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
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, host_client = svs.clients;j < svs.maxclients;j++, host_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 *s = PF_VarString(0);
2694 G_FLOAT(OFS_RETURN) = atof(s);
2697 //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
2701 char *modestring, *filename;
2702 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2703 if (pr_files[filenum] == NULL)
2705 if (filenum >= MAX_PRFILES)
2707 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2708 G_FLOAT(OFS_RETURN) = -2;
2711 mode = G_FLOAT(OFS_PARM1);
2714 case 0: // FILE_READ
2717 case 1: // FILE_APPEND
2720 case 2: // FILE_WRITE
2724 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2725 G_FLOAT(OFS_RETURN) = -3;
2728 filename = G_STRING(OFS_PARM0);
2729 // .. is parent directory on many platforms
2730 // / is parent directory on Amiga
2731 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2732 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2733 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2735 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2736 G_FLOAT(OFS_RETURN) = -4;
2739 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2740 if (pr_files[filenum] == NULL)
2741 G_FLOAT(OFS_RETURN) = -1;
2743 G_FLOAT(OFS_RETURN) = filenum;
2746 //void(float fhandle) fclose = #111; // closes a file
2747 void PF_fclose(void)
2749 int filenum = G_FLOAT(OFS_PARM0);
2750 if (filenum < 0 || filenum >= MAX_PRFILES)
2752 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2755 if (pr_files[filenum] == NULL)
2757 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2760 FS_Close(pr_files[filenum]);
2761 pr_files[filenum] = NULL;
2764 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2768 static char string[MAX_VARSTRING];
2769 int filenum = G_FLOAT(OFS_PARM0);
2770 if (filenum < 0 || filenum >= MAX_PRFILES)
2772 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2775 if (pr_files[filenum] == NULL)
2777 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2783 c = FS_Getc(pr_files[filenum]);
2784 if (c == '\r' || c == '\n' || c < 0)
2786 if (end < MAX_VARSTRING - 1)
2790 // remove \n following \r
2792 c = FS_Getc(pr_files[filenum]);
2793 if (developer.integer)
2794 Con_Printf("fgets: %s\n", string);
2796 G_INT(OFS_RETURN) = PR_SetString(string);
2798 G_INT(OFS_RETURN) = 0;
2801 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2805 char *s = PF_VarString(1);
2806 int filenum = G_FLOAT(OFS_PARM0);
2807 if (filenum < 0 || filenum >= MAX_PRFILES)
2809 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2812 if (pr_files[filenum] == NULL)
2814 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2817 if ((stringlength = strlen(s)))
2818 FS_Write(pr_files[filenum], s, stringlength);
2819 if (developer.integer)
2820 Con_Printf("fputs: %s\n", s);
2823 //float(string s) strlen = #114; // returns how many characters are in a string
2824 void PF_strlen(void)
2827 s = G_STRING(OFS_PARM0);
2829 G_FLOAT(OFS_RETURN) = strlen(s);
2831 G_FLOAT(OFS_RETURN) = 0;
2834 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2835 void PF_strcat(void)
2837 char *s = PF_VarString(0);
2838 G_INT(OFS_RETURN) = PR_SetString(s);
2841 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2842 void PF_substring(void)
2844 int i, start, length;
2845 char *s, *string = PR_GetTempString();
2846 s = G_STRING(OFS_PARM0);
2847 start = G_FLOAT(OFS_PARM1);
2848 length = G_FLOAT(OFS_PARM2);
2851 for (i = 0;i < start && *s;i++, s++);
2852 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2855 G_INT(OFS_RETURN) = PR_SetString(string);
2858 //vector(string s) stov = #117; // returns vector value from a string
2861 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2864 //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)
2865 void PF_strzone(void)
2868 in = G_STRING(OFS_PARM0);
2869 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2871 G_INT(OFS_RETURN) = PR_SetString(out);
2874 //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!!!)
2875 void PF_strunzone(void)
2877 Mem_Free(G_STRING(OFS_PARM0));
2880 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2881 //this function originally written by KrimZon, made shorter by LordHavoc
2882 void PF_clientcommand (void)
2884 client_t *temp_client;
2887 //find client for this entity
2888 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2889 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2891 Con_Printf("PF_clientcommand: entity is not a client");
2895 temp_client = host_client;
2896 host_client = svs.clients + i;
2897 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2898 host_client = temp_client;
2901 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2902 //this function originally written by KrimZon, made shorter by LordHavoc
2903 char **tokens = NULL;
2904 int max_tokens, num_tokens = 0;
2905 void PF_tokenize (void)
2909 str = G_STRING(OFS_PARM0);
2914 for (i=0;i<num_tokens;i++)
2920 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2921 max_tokens = strlen(str);
2923 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2925 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2926 strcpy(tokens[num_tokens], com_token);
2929 G_FLOAT(OFS_RETURN) = num_tokens;
2932 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2933 //this function originally written by KrimZon, made shorter by LordHavoc
2936 int token_num = G_FLOAT(OFS_PARM0);
2937 if (token_num >= 0 && token_num < num_tokens)
2938 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2940 G_INT(OFS_RETURN) = PR_SetString("");
2943 //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)
2944 void PF_setattachment (void)
2946 edict_t *e = G_EDICT(OFS_PARM0);
2947 edict_t *tagentity = G_EDICT(OFS_PARM1);
2948 char *tagname = G_STRING(OFS_PARM2);
2953 if (tagentity == NULL)
2954 tagentity = sv.edicts;
2956 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2958 v->edict = EDICT_TO_PROG(tagentity);
2960 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2963 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2965 modelindex = (int)tagentity->v->modelindex;
2966 if (modelindex >= 0 && modelindex < MAX_MODELS)
2968 model = sv.models[modelindex];
2969 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2970 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2971 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2973 if (v->_float == 0 && model->alias.aliasnum_tags)
2974 for (i = 0;i < model->alias.aliasnum_tags;i++)
2975 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2978 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);
2981 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));
2986 builtin_t pr_builtin[] =
2989 PF_makevectors, // #1 void(entity e) makevectors
2990 PF_setorigin, // #2 void(entity e, vector o) setorigin
2991 PF_setmodel, // #3 void(entity e, string m) setmodel
2992 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2993 NULL, // #5 void(entity e, vector min, vector max) setabssize
2994 PF_break, // #6 void() break
2995 PF_random, // #7 float() random
2996 PF_sound, // #8 void(entity e, float chan, string samp) sound
2997 PF_normalize, // #9 vector(vector v) normalize
2998 PF_error, // #10 void(string e) error
2999 PF_objerror, // #11 void(string e) objerror
3000 PF_vlen, // #12 float(vector v) vlen
3001 PF_vectoyaw, // #13 float(vector v) vectoyaw
3002 PF_Spawn, // #14 entity() spawn
3003 PF_Remove, // #15 void(entity e) remove
3004 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3005 PF_checkclient, // #17 entity() clientlist
3006 PF_Find, // #18 entity(entity start, .string fld, string match) find
3007 PF_precache_sound, // #19 void(string s) precache_sound
3008 PF_precache_model, // #20 void(string s) precache_model
3009 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3010 PF_findradius, // #22 entity(vector org, float rad) findradius
3011 PF_bprint, // #23 void(string s) bprint
3012 PF_sprint, // #24 void(entity client, string s) sprint
3013 PF_dprint, // #25 void(string s) dprint
3014 PF_ftos, // #26 void(string s) ftos
3015 PF_vtos, // #27 void(string s) vtos
3016 PF_coredump, // #28 void() coredump
3017 PF_traceon, // #29 void() traceon
3018 PF_traceoff, // #30 void() traceoff
3019 PF_eprint, // #31 void(entity e) eprint
3020 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3022 PF_droptofloor, // #34 float() droptofloor
3023 PF_lightstyle, // #35 void(float style, string value) lightstyle
3024 PF_rint, // #36 float(float v) rint
3025 PF_floor, // #37 float(float v) floor
3026 PF_ceil, // #38 float(float v) ceil
3028 PF_checkbottom, // #40 float(entity e) checkbottom
3029 PF_pointcontents , // #41 float(vector v) pointcontents
3031 PF_fabs, // #43 float(float f) fabs
3032 PF_aim, // #44 vector(entity e, float speed) aim
3033 PF_cvar, // #45 float(string s) cvar
3034 PF_localcmd, // #46 void(string s) localcmd
3035 PF_nextent, // #47 entity(entity e) nextent
3036 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3037 PF_changeyaw, // #49 void() ChangeYaw
3039 PF_vectoangles, // #51 vector(vector v) vectoangles
3040 PF_WriteByte, // #52 void(float to, float f) WriteByte
3041 PF_WriteChar, // #53 void(float to, float f) WriteChar
3042 PF_WriteShort, // #54 void(float to, float f) WriteShort
3043 PF_WriteLong, // #55 void(float to, float f) WriteLong
3044 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3045 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3046 PF_WriteString, // #58 void(float to, string s) WriteString
3047 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3048 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3049 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3050 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3051 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3052 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3053 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3055 SV_MoveToGoal, // #67 void(float step) movetogoal
3056 PF_precache_file, // #68 string(string s) precache_file
3057 PF_makestatic, // #69 void(entity e) makestatic
3058 PF_changelevel, // #70 void(string s) changelevel
3060 PF_cvar_set, // #72 void(string var, string val) cvar_set
3061 PF_centerprint, // #73 void(entity client, strings) centerprint
3062 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3063 PF_precache_model, // #75 string(string s) precache_model2
3064 PF_precache_sound, // #76 string(string s) precache_sound2
3065 PF_precache_file, // #77 string(string s) precache_file2
3066 PF_setspawnparms, // #78 void(entity e) setspawnparms
3069 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3078 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3079 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3080 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3081 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3082 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3083 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3084 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3085 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3086 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3087 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3098 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3099 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3100 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3101 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3102 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3103 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3104 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3105 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3106 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3107 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3108 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3109 a a a a a a a a // #120-199
3110 a a a a a a a a a a // #200-299
3111 a a a a a a a a a a // #300-399
3112 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3113 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3114 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3115 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3116 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3117 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3118 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3119 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3120 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3121 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3122 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3123 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3124 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3125 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3126 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3127 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3128 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3129 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3130 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3131 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3132 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3133 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3134 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3135 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3136 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3137 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3138 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3139 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3140 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3141 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3142 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3143 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3144 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3145 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3146 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3147 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3148 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3149 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3150 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3151 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3152 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3153 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3154 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3155 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3162 a a a a a // #450-499 (LordHavoc)
3165 builtin_t *pr_builtins = pr_builtin;
3166 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3168 void PR_Cmd_Init(void)
3170 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3174 void PR_Cmd_Reset(void)
3176 Mem_EmptyPool(pr_strings_mempool);
3177 PR_Files_CloseAll();