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_VECTORVECTORS "
116 "DP_SV_DRAWONLYTOCLIENT "
118 "DP_SV_EXTERIORMODELTOCLIENT "
119 "DP_SV_NODRAWTOCLIENT "
120 "DP_SV_PLAYERPHYSICS "
126 "DP_TE_EXPLOSIONRGB "
128 "DP_TE_PARTICLECUBE "
129 "DP_TE_PARTICLERAIN "
130 "DP_TE_PARTICLESNOW "
132 "DP_TE_QUADEFFECTS1 "
135 "DP_TE_STANDARDEFFECTBUILTINS "
138 "KRIMZON_SV_PARSECLIENTCOMMAND "
144 qboolean checkextension(char *name)
149 for (e = ENGINE_EXTENSIONS;*e;e++)
156 while (*e && *e != ' ')
158 if (e - start == len)
159 if (!strncasecmp(start, name, len))
169 returns true if the extension is supported by the server
171 checkextension(extensionname)
174 void PF_checkextension (void)
176 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
183 This is a TERMINAL error, which will kill off the entire server.
192 char string[STRINGTEMP_LENGTH];
194 PF_VarString(0, string, sizeof(string));
195 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
196 ed = PROG_TO_EDICT(pr_global_struct->self);
199 Host_Error ("Program error");
206 Dumps out self, then an error message. The program is aborted and self is
207 removed, but the level can continue.
212 void PF_objerror (void)
215 char string[STRINGTEMP_LENGTH];
217 PF_VarString(0, string, sizeof(string));
218 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
219 ed = PROG_TO_EDICT(pr_global_struct->self);
229 Writes new values for v_forward, v_up, and v_right based on angles
233 void PF_makevectors (void)
235 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
242 Writes new values for v_forward, v_up, and v_right based on the given forward vector
243 vectorvectors(vector, vector)
246 void PF_vectorvectors (void)
248 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
249 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
256 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.
258 setorigin (entity, origin)
261 void PF_setorigin (void)
266 e = G_EDICT(OFS_PARM0);
267 org = G_VECTOR(OFS_PARM1);
268 VectorCopy (org, e->v->origin);
269 SV_LinkEdict (e, false);
273 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
277 for (i=0 ; i<3 ; i++)
279 Host_Error ("backwards mins/maxs");
281 // set derived values
282 VectorCopy (min, e->v->mins);
283 VectorCopy (max, e->v->maxs);
284 VectorSubtract (max, min, e->v->size);
286 SV_LinkEdict (e, false);
293 the size box is rotated by the current angle
294 LordHavoc: no it isn't...
296 setsize (entity, minvector, maxvector)
299 void PF_setsize (void)
304 e = G_EDICT(OFS_PARM0);
305 min = G_VECTOR(OFS_PARM1);
306 max = G_VECTOR(OFS_PARM2);
307 SetMinMaxSize (e, min, max, false);
315 setmodel(entity, model)
318 void PF_setmodel (void)
325 e = G_EDICT(OFS_PARM0);
326 m = G_STRING(OFS_PARM1);
328 // check to see if model was properly precached
329 for (i=0, check = sv.model_precache ; *check ; i++, check++)
330 if (!strcmp(*check, m))
334 Host_Error ("no precache: %s\n", m);
337 e->v->model = PR_SetString(*check);
338 e->v->modelindex = i;
340 mod = sv.models[ (int)e->v->modelindex];
343 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
345 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
352 broadcast print to everyone on server
357 void PF_bprint (void)
359 char string[STRINGTEMP_LENGTH];
360 PF_VarString(0, string, sizeof(string));
361 SV_BroadcastPrintf("%s", string);
368 single print to a specific client
370 sprint(clientent, value)
373 void PF_sprint (void)
377 char string[STRINGTEMP_LENGTH];
379 entnum = G_EDICTNUM(OFS_PARM0);
381 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
383 Con_Printf ("tried to sprint to a non-client\n");
387 client = svs.clients + entnum-1;
388 if (!client->netconnection)
390 PF_VarString(1, string, sizeof(string));
391 MSG_WriteChar(&client->message,svc_print);
392 MSG_WriteString(&client->message, string);
400 single print to a specific client
402 centerprint(clientent, value)
405 void PF_centerprint (void)
409 char string[STRINGTEMP_LENGTH];
411 entnum = G_EDICTNUM(OFS_PARM0);
413 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
415 Con_Printf ("tried to sprint to a non-client\n");
419 client = svs.clients + entnum-1;
420 if (!client->netconnection)
422 PF_VarString(1, string, sizeof(string));
423 MSG_WriteChar(&client->message,svc_centerprint);
424 MSG_WriteString(&client->message, string);
432 vector normalize(vector)
435 void PF_normalize (void)
441 value1 = G_VECTOR(OFS_PARM0);
443 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
447 newvalue[0] = newvalue[1] = newvalue[2] = 0;
451 newvalue[0] = value1[0] * new;
452 newvalue[1] = value1[1] * new;
453 newvalue[2] = value1[2] * new;
456 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
471 value1 = G_VECTOR(OFS_PARM0);
473 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
476 G_FLOAT(OFS_RETURN) = new;
483 float vectoyaw(vector)
486 void PF_vectoyaw (void)
491 value1 = G_VECTOR(OFS_PARM0);
493 if (value1[1] == 0 && value1[0] == 0)
497 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
502 G_FLOAT(OFS_RETURN) = yaw;
510 vector vectoangles(vector)
513 void PF_vectoangles (void)
519 value1 = G_VECTOR(OFS_PARM0);
521 if (value1[1] == 0 && value1[0] == 0)
531 // LordHavoc: optimized a bit
534 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
538 else if (value1[1] > 0)
543 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
544 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
549 G_FLOAT(OFS_RETURN+0) = pitch;
550 G_FLOAT(OFS_RETURN+1) = yaw;
551 G_FLOAT(OFS_RETURN+2) = 0;
558 Returns a number from 0<= num < 1
563 void PF_random (void)
567 num = (rand ()&0x7fff) / ((float)0x7fff);
569 G_FLOAT(OFS_RETURN) = num;
576 particle(origin, color, count)
579 void PF_particle (void)
585 org = G_VECTOR(OFS_PARM0);
586 dir = G_VECTOR(OFS_PARM1);
587 color = G_FLOAT(OFS_PARM2);
588 count = G_FLOAT(OFS_PARM3);
589 SV_StartParticle (org, dir, color, count);
599 void PF_ambientsound (void)
604 float vol, attenuation;
605 int i, soundnum, large;
607 pos = G_VECTOR (OFS_PARM0);
608 samp = G_STRING(OFS_PARM1);
609 vol = G_FLOAT(OFS_PARM2);
610 attenuation = G_FLOAT(OFS_PARM3);
612 // check to see if samp was properly precached
613 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
614 if (!strcmp(*check,samp))
619 Con_Printf ("no precache: %s\n", samp);
627 // add an svc_spawnambient command to the level signon packet
630 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
632 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
634 for (i=0 ; i<3 ; i++)
635 MSG_WriteDPCoord(&sv.signon, pos[i]);
638 MSG_WriteShort (&sv.signon, soundnum);
640 MSG_WriteByte (&sv.signon, soundnum);
642 MSG_WriteByte (&sv.signon, vol*255);
643 MSG_WriteByte (&sv.signon, attenuation*64);
651 Each entity can have eight independant sound sources, like voice,
654 Channel 0 is an auto-allocate channel, the others override anything
655 already running on that entity/channel pair.
657 An attenuation of 0 will play full volume everywhere in the level.
658 Larger attenuations will drop off.
670 entity = G_EDICT(OFS_PARM0);
671 channel = G_FLOAT(OFS_PARM1);
672 sample = G_STRING(OFS_PARM2);
673 volume = G_FLOAT(OFS_PARM3) * 255;
674 attenuation = G_FLOAT(OFS_PARM4);
676 if (volume < 0 || volume > 255)
677 Host_Error ("SV_StartSound: volume = %i", volume);
679 if (attenuation < 0 || attenuation > 4)
680 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
682 if (channel < 0 || channel > 7)
683 Host_Error ("SV_StartSound: channel = %i", channel);
685 SV_StartSound (entity, channel, sample, volume, attenuation);
697 Host_Error ("break statement");
704 Used for use tracing and shot targeting
705 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
706 if the tryents flag is set.
708 traceline (vector1, vector2, tryents)
711 void PF_traceline (void)
718 pr_xfunction->builtinsprofile += 30;
720 v1 = G_VECTOR(OFS_PARM0);
721 v2 = G_VECTOR(OFS_PARM1);
722 nomonsters = G_FLOAT(OFS_PARM2);
723 ent = G_EDICT(OFS_PARM3);
725 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
727 pr_global_struct->trace_allsolid = trace.allsolid;
728 pr_global_struct->trace_startsolid = trace.startsolid;
729 pr_global_struct->trace_fraction = trace.fraction;
730 pr_global_struct->trace_inwater = trace.inwater;
731 pr_global_struct->trace_inopen = trace.inopen;
732 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
733 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
734 pr_global_struct->trace_plane_dist = trace.plane.dist;
736 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
738 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
739 // FIXME: add trace_endcontents
747 Used for use tracing and shot targeting
748 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
749 if the tryents flag is set.
751 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
754 // LordHavoc: added this for my own use, VERY useful, similar to traceline
755 void PF_tracebox (void)
757 float *v1, *v2, *m1, *m2;
762 pr_xfunction->builtinsprofile += 30;
764 v1 = G_VECTOR(OFS_PARM0);
765 m1 = G_VECTOR(OFS_PARM1);
766 m2 = G_VECTOR(OFS_PARM2);
767 v2 = G_VECTOR(OFS_PARM3);
768 nomonsters = G_FLOAT(OFS_PARM4);
769 ent = G_EDICT(OFS_PARM5);
771 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
773 pr_global_struct->trace_allsolid = trace.allsolid;
774 pr_global_struct->trace_startsolid = trace.startsolid;
775 pr_global_struct->trace_fraction = trace.fraction;
776 pr_global_struct->trace_inwater = trace.inwater;
777 pr_global_struct->trace_inopen = trace.inopen;
778 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
779 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
780 pr_global_struct->trace_plane_dist = trace.plane.dist;
782 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
784 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
787 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
788 void PF_TraceToss (void)
794 pr_xfunction->builtinsprofile += 600;
796 ent = G_EDICT(OFS_PARM0);
797 ignore = G_EDICT(OFS_PARM1);
799 trace = SV_Trace_Toss (ent, ignore);
801 pr_global_struct->trace_allsolid = trace.allsolid;
802 pr_global_struct->trace_startsolid = trace.startsolid;
803 pr_global_struct->trace_fraction = trace.fraction;
804 pr_global_struct->trace_inwater = trace.inwater;
805 pr_global_struct->trace_inopen = trace.inopen;
806 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
807 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
808 pr_global_struct->trace_plane_dist = trace.plane.dist;
810 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
812 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
820 Returns true if the given entity can move to the given position from it's
821 current position by walking or rolling.
823 scalar checkpos (entity, vector)
826 void PF_checkpos (void)
830 //============================================================================
833 qbyte checkpvs[MAX_MAP_LEAFS/8];
835 int PF_newcheckclient (int check)
841 // cycle to the next one
843 check = bound(1, check, svs.maxclients);
844 if (check == svs.maxclients)
852 pr_xfunction->builtinsprofile++;
854 if (i == svs.maxclients+1)
856 // look up the client's edict
858 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
859 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
861 // found a valid client (possibly the same one again)
865 // get the PVS for the entity
866 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
868 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
869 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
878 Returns a client (or object that has a client enemy) that would be a
881 If there is more than one valid option, they are cycled each frame
883 If (self.origin + self.viewofs) is not in the PVS of the current target,
884 it is not returned at all.
889 int c_invis, c_notvis;
890 void PF_checkclient (void)
895 // find a new check if on a new frame
896 if (sv.time - sv.lastchecktime >= 0.1)
898 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
899 sv.lastchecktime = sv.time;
902 // return check if it might be visible
903 ent = EDICT_NUM(sv.lastcheck);
904 if (ent->e->free || ent->v->health <= 0)
906 RETURN_EDICT(sv.edicts);
910 // if current entity can't possibly see the check entity, return 0
911 self = PROG_TO_EDICT(pr_global_struct->self);
912 VectorAdd(self->v->origin, self->v->view_ofs, view);
913 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
916 RETURN_EDICT(sv.edicts);
920 // might be able to see it
925 //============================================================================
932 Sends text over to the client's execution buffer
934 stuffcmd (clientent, value)
937 void PF_stuffcmd (void)
943 entnum = G_EDICTNUM(OFS_PARM0);
944 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
946 Con_Printf("Can't stuffcmd to a non-client");
949 str = G_STRING(OFS_PARM1);
952 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
953 Host_ClientCommands ("%s", str);
961 Sends text over to the client's execution buffer
966 void PF_localcmd (void)
968 Cbuf_AddText(G_STRING(OFS_PARM0));
980 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
990 void PF_cvar_set (void)
992 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
999 Returns a chain of entities that have origins within a spherical area
1001 findradius (origin, radius)
1004 void PF_findradius (void)
1006 edict_t *ent, *chain;
1013 chain = (edict_t *)sv.edicts;
1015 org = G_VECTOR(OFS_PARM0);
1016 radius = G_FLOAT(OFS_PARM1);
1017 radius2 = radius * radius;
1019 ent = NEXT_EDICT(sv.edicts);
1020 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1022 pr_xfunction->builtinsprofile++;
1025 if (ent->v->solid == SOLID_NOT)
1028 // LordHavoc: compare against bounding box rather than center,
1029 // and use DotProduct instead of Length, major speedup
1030 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1031 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1032 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1033 if (DotProduct(eorg, eorg) > radius2)
1036 ent->v->chain = EDICT_TO_PROG(chain);
1040 RETURN_EDICT(chain);
1049 void PF_dprint (void)
1051 char string[STRINGTEMP_LENGTH];
1052 if (developer.integer)
1054 PF_VarString(0, string, sizeof(string));
1055 Con_Printf("%s",string);
1063 v = G_FLOAT(OFS_PARM0);
1065 s = PR_GetTempString();
1066 if ((float)((int)v) == v)
1067 sprintf(s, "%i", (int)v);
1069 sprintf(s, "%f", v);
1070 G_INT(OFS_RETURN) = PR_SetString(s);
1076 v = G_FLOAT(OFS_PARM0);
1077 G_FLOAT(OFS_RETURN) = fabs(v);
1083 s = PR_GetTempString();
1084 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1085 G_INT(OFS_RETURN) = PR_SetString(s);
1091 s = PR_GetTempString();
1092 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1093 G_INT(OFS_RETURN) = PR_SetString(s);
1096 void PF_Spawn (void)
1099 pr_xfunction->builtinsprofile += 20;
1104 void PF_Remove (void)
1107 pr_xfunction->builtinsprofile += 20;
1109 ed = G_EDICT(OFS_PARM0);
1110 if (ed == sv.edicts)
1111 Host_Error("remove: tried to remove world\n");
1112 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1113 Host_Error("remove: tried to remove a client\n");
1118 // entity (entity start, .string field, string match) find = #5;
1126 e = G_EDICTNUM(OFS_PARM0);
1127 f = G_INT(OFS_PARM1);
1128 s = G_STRING(OFS_PARM2);
1131 RETURN_EDICT(sv.edicts);
1135 for (e++ ; e < sv.num_edicts ; e++)
1137 pr_xfunction->builtinsprofile++;
1151 RETURN_EDICT(sv.edicts);
1154 // LordHavoc: added this for searching float, int, and entity reference fields
1155 void PF_FindFloat (void)
1162 e = G_EDICTNUM(OFS_PARM0);
1163 f = G_INT(OFS_PARM1);
1164 s = G_FLOAT(OFS_PARM2);
1166 for (e++ ; e < sv.num_edicts ; e++)
1168 pr_xfunction->builtinsprofile++;
1172 if (E_FLOAT(ed,f) == s)
1179 RETURN_EDICT(sv.edicts);
1182 // chained search for strings in entity fields
1183 // entity(.string field, string match) findchain = #402;
1184 void PF_findchain (void)
1189 edict_t *ent, *chain;
1191 chain = (edict_t *)sv.edicts;
1193 f = G_INT(OFS_PARM0);
1194 s = G_STRING(OFS_PARM1);
1197 RETURN_EDICT(sv.edicts);
1201 ent = NEXT_EDICT(sv.edicts);
1202 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1204 pr_xfunction->builtinsprofile++;
1207 t = E_STRING(ent,f);
1213 ent->v->chain = EDICT_TO_PROG(chain);
1217 RETURN_EDICT(chain);
1220 // LordHavoc: chained search for float, int, and entity reference fields
1221 // entity(.string field, float match) findchainfloat = #403;
1222 void PF_findchainfloat (void)
1227 edict_t *ent, *chain;
1229 chain = (edict_t *)sv.edicts;
1231 f = G_INT(OFS_PARM0);
1232 s = G_FLOAT(OFS_PARM1);
1234 ent = NEXT_EDICT(sv.edicts);
1235 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1237 pr_xfunction->builtinsprofile++;
1240 if (E_FLOAT(ent,f) != s)
1243 ent->v->chain = EDICT_TO_PROG(chain);
1247 RETURN_EDICT(chain);
1250 void PR_CheckEmptyString (char *s)
1253 Host_Error ("Bad string");
1256 void PF_precache_file (void)
1257 { // precache_file is only used to copy files with qcc, it does nothing
1258 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1261 void PF_precache_sound (void)
1266 if (sv.state != ss_loading)
1267 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1269 s = G_STRING(OFS_PARM0);
1270 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1271 PR_CheckEmptyString (s);
1273 for (i=0 ; i<MAX_SOUNDS ; i++)
1275 if (!sv.sound_precache[i])
1277 sv.sound_precache[i] = s;
1280 if (!strcmp(sv.sound_precache[i], s))
1283 Host_Error ("PF_precache_sound: overflow");
1286 void PF_precache_model (void)
1291 if (sv.state != ss_loading)
1292 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1294 s = G_STRING(OFS_PARM0);
1295 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1297 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1298 PR_CheckEmptyString (s);
1300 for (i=0 ; i<MAX_MODELS ; i++)
1302 if (!sv.model_precache[i])
1304 sv.model_precache[i] = s;
1305 sv.models[i] = Mod_ForName (s, true, false, false);
1308 if (!strcmp(sv.model_precache[i], s))
1311 Host_Error ("PF_precache_model: overflow");
1315 void PF_coredump (void)
1320 void PF_traceon (void)
1325 void PF_traceoff (void)
1330 void PF_eprint (void)
1332 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1339 float(float yaw, float dist) walkmove
1342 void PF_walkmove (void)
1350 ent = PROG_TO_EDICT(pr_global_struct->self);
1351 yaw = G_FLOAT(OFS_PARM0);
1352 dist = G_FLOAT(OFS_PARM1);
1354 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1356 G_FLOAT(OFS_RETURN) = 0;
1360 yaw = yaw*M_PI*2 / 360;
1362 move[0] = cos(yaw)*dist;
1363 move[1] = sin(yaw)*dist;
1366 // save program state, because SV_movestep may call other progs
1367 oldf = pr_xfunction;
1368 oldself = pr_global_struct->self;
1370 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1373 // restore program state
1374 pr_xfunction = oldf;
1375 pr_global_struct->self = oldself;
1385 void PF_droptofloor (void)
1391 ent = PROG_TO_EDICT(pr_global_struct->self);
1393 VectorCopy (ent->v->origin, end);
1396 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1398 if (trace.fraction == 1)
1399 G_FLOAT(OFS_RETURN) = 0;
1402 VectorCopy (trace.endpos, ent->v->origin);
1403 SV_LinkEdict (ent, false);
1404 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1405 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1406 G_FLOAT(OFS_RETURN) = 1;
1407 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1408 ent->e->suspendedinairflag = true;
1416 void(float style, string value) lightstyle
1419 void PF_lightstyle (void)
1426 style = G_FLOAT(OFS_PARM0);
1427 val = G_STRING(OFS_PARM1);
1429 // change the string in sv
1430 sv.lightstyles[style] = val;
1432 // send message to all clients on this server
1433 if (sv.state != ss_active)
1436 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1438 if (client->netconnection)
1440 MSG_WriteChar (&client->message, svc_lightstyle);
1441 MSG_WriteChar (&client->message,style);
1442 MSG_WriteString (&client->message, val);
1450 f = G_FLOAT(OFS_PARM0);
1452 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1454 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1456 void PF_floor (void)
1458 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1462 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1471 void PF_checkbottom (void)
1473 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1481 void PF_pointcontents (void)
1483 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1490 entity nextent(entity)
1493 void PF_nextent (void)
1498 i = G_EDICTNUM(OFS_PARM0);
1501 pr_xfunction->builtinsprofile++;
1503 if (i == sv.num_edicts)
1505 RETURN_EDICT(sv.edicts);
1521 Pick a vector for the player to shoot along
1522 vector aim(entity, missilespeed)
1527 edict_t *ent, *check, *bestent;
1528 vec3_t start, dir, end, bestdir;
1531 float dist, bestdist;
1534 ent = G_EDICT(OFS_PARM0);
1535 speed = G_FLOAT(OFS_PARM1);
1537 VectorCopy (ent->v->origin, start);
1540 // try sending a trace straight
1541 VectorCopy (pr_global_struct->v_forward, dir);
1542 VectorMA (start, 2048, dir, end);
1543 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1544 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1545 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1547 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1552 // try all possible entities
1553 VectorCopy (dir, bestdir);
1554 bestdist = sv_aim.value;
1557 check = NEXT_EDICT(sv.edicts);
1558 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1560 pr_xfunction->builtinsprofile++;
1561 if (check->v->takedamage != DAMAGE_AIM)
1565 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1566 continue; // don't aim at teammate
1567 for (j=0 ; j<3 ; j++)
1568 end[j] = check->v->origin[j]
1569 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1570 VectorSubtract (end, start, dir);
1571 VectorNormalize (dir);
1572 dist = DotProduct (dir, pr_global_struct->v_forward);
1573 if (dist < bestdist)
1574 continue; // to far to turn
1575 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1576 if (tr.ent == check)
1577 { // can shoot at this one
1585 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1586 dist = DotProduct (dir, pr_global_struct->v_forward);
1587 VectorScale (pr_global_struct->v_forward, dist, end);
1589 VectorNormalize (end);
1590 VectorCopy (end, G_VECTOR(OFS_RETURN));
1594 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1602 This was a major timewaster in progs, so it was converted to C
1605 void PF_changeyaw (void)
1608 float ideal, current, move, speed;
1610 ent = PROG_TO_EDICT(pr_global_struct->self);
1611 current = ANGLEMOD(ent->v->angles[1]);
1612 ideal = ent->v->ideal_yaw;
1613 speed = ent->v->yaw_speed;
1615 if (current == ideal)
1617 move = ideal - current;
1618 if (ideal > current)
1639 ent->v->angles[1] = ANGLEMOD (current + move);
1647 void PF_changepitch (void)
1650 float ideal, current, move, speed;
1653 ent = G_EDICT(OFS_PARM0);
1654 current = ANGLEMOD( ent->v->angles[0] );
1655 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1656 ideal = val->_float;
1659 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1662 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1663 speed = val->_float;
1666 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1670 if (current == ideal)
1672 move = ideal - current;
1673 if (ideal > current)
1694 ent->v->angles[0] = ANGLEMOD (current + move);
1698 ===============================================================================
1702 ===============================================================================
1705 #define MSG_BROADCAST 0 // unreliable to all
1706 #define MSG_ONE 1 // reliable to one (msg_entity)
1707 #define MSG_ALL 2 // reliable to all
1708 #define MSG_INIT 3 // write to the init string
1710 sizebuf_t *WriteDest (void)
1716 dest = G_FLOAT(OFS_PARM0);
1720 return &sv.datagram;
1723 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1724 entnum = NUM_FOR_EDICT(ent);
1725 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1726 Con_Printf("WriteDest: tried to write to non-client\n");
1727 return &svs.clients[entnum-1].message;
1730 return &sv.reliable_datagram;
1736 Host_Error ("WriteDest: bad destination");
1743 void PF_WriteByte (void)
1745 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1748 void PF_WriteChar (void)
1750 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1753 void PF_WriteShort (void)
1755 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1758 void PF_WriteLong (void)
1760 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1763 void PF_WriteAngle (void)
1765 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1768 void PF_WriteCoord (void)
1770 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1773 void PF_WriteString (void)
1775 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1779 void PF_WriteEntity (void)
1781 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1784 //=============================================================================
1786 void PF_makestatic (void)
1791 ent = G_EDICT(OFS_PARM0);
1794 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1799 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1800 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1801 MSG_WriteShort (&sv.signon, ent->v->frame);
1805 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1806 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1807 MSG_WriteByte (&sv.signon, ent->v->frame);
1810 MSG_WriteByte (&sv.signon, ent->v->colormap);
1811 MSG_WriteByte (&sv.signon, ent->v->skin);
1812 for (i=0 ; i<3 ; i++)
1814 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1815 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1818 // throw the entity away now
1822 //=============================================================================
1829 void PF_setspawnparms (void)
1835 ent = G_EDICT(OFS_PARM0);
1836 i = NUM_FOR_EDICT(ent);
1837 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1839 Con_Printf("tried to setspawnparms on a non-client\n");
1843 // copy spawn parms out of the client_t
1844 client = svs.clients + i-1;
1845 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1846 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1854 void PF_changelevel (void)
1858 // make sure we don't issue two changelevels
1859 if (svs.changelevel_issued)
1861 svs.changelevel_issued = true;
1863 s = G_STRING(OFS_PARM0);
1864 Cbuf_AddText (va("changelevel %s\n",s));
1869 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1874 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1879 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1886 Returns a vector of length < 1
1891 void PF_randomvec (void)
1896 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1897 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1898 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1900 while (DotProduct(temp, temp) >= 1);
1901 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1908 Returns a color vector indicating the lighting at the requested point.
1910 (Internal Operation note: actually measures the light beneath the point, just like
1911 the model lighting on the client)
1916 void PF_GetLight (void)
1918 vec3_t ambientcolor, diffusecolor, diffusenormal;
1920 p = G_VECTOR(OFS_PARM0);
1921 VectorClear(ambientcolor);
1922 VectorClear(diffusecolor);
1923 VectorClear(diffusenormal);
1924 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1925 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1926 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1929 #define MAX_QC_CVARS 128
1930 cvar_t qc_cvar[MAX_QC_CVARS];
1933 void PF_registercvar (void)
1937 name = G_STRING(OFS_PARM0);
1938 value = G_STRING(OFS_PARM1);
1939 G_FLOAT(OFS_RETURN) = 0;
1940 // first check to see if it has already been defined
1941 if (Cvar_FindVar (name))
1944 // check for overlap with a command
1945 if (Cmd_Exists (name))
1947 Con_Printf ("PF_registercvar: %s is a command\n", name);
1951 if (currentqc_cvar >= MAX_QC_CVARS)
1952 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1954 // copy the name and value
1955 variable = &qc_cvar[currentqc_cvar++];
1956 variable->name = Z_Malloc (strlen(name)+1);
1957 strcpy (variable->name, name);
1958 variable->string = Z_Malloc (strlen(value)+1);
1959 strcpy (variable->string, value);
1960 variable->value = atof (value);
1962 Cvar_RegisterVariable(variable);
1963 G_FLOAT(OFS_RETURN) = 1; // success
1970 returns the minimum of two supplied floats
1977 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1979 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1980 else if (pr_argc >= 3)
1983 float f = G_FLOAT(OFS_PARM0);
1984 for (i = 1;i < pr_argc;i++)
1985 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1986 f = G_FLOAT((OFS_PARM0+i*3));
1987 G_FLOAT(OFS_RETURN) = f;
1990 Host_Error("min: must supply at least 2 floats\n");
1997 returns the maximum of two supplied floats
2004 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2006 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2007 else if (pr_argc >= 3)
2010 float f = G_FLOAT(OFS_PARM0);
2011 for (i = 1;i < pr_argc;i++)
2012 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2013 f = G_FLOAT((OFS_PARM0+i*3));
2014 G_FLOAT(OFS_RETURN) = f;
2017 Host_Error("max: must supply at least 2 floats\n");
2024 returns number bounded by supplied range
2026 min(min, value, max)
2029 void PF_bound (void)
2031 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2038 returns a raised to power b
2045 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2052 copies data from one entity to another
2054 copyentity(src, dst)
2057 void PF_copyentity (void)
2060 in = G_EDICT(OFS_PARM0);
2061 out = G_EDICT(OFS_PARM1);
2062 memcpy(out->v, in->v, progs->entityfields * 4);
2069 sets the color of a client and broadcasts the update to all connected clients
2071 setcolor(clientent, value)
2074 void PF_setcolor (void)
2080 entnum = G_EDICTNUM(OFS_PARM0);
2081 i = G_FLOAT(OFS_PARM1);
2083 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2085 Con_Printf ("tried to setcolor a non-client\n");
2089 client = svs.clients + entnum-1;
2090 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2093 client->old_colors = i;
2094 client->edict->v->team = (i & 15) + 1;
2096 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2097 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2098 MSG_WriteByte (&sv.reliable_datagram, i);
2105 effect(origin, modelname, startframe, framecount, framerate)
2108 void PF_effect (void)
2111 s = G_STRING(OFS_PARM1);
2113 Host_Error("effect: no model specified\n");
2115 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2118 void PF_te_blood (void)
2120 if (G_FLOAT(OFS_PARM2) < 1)
2122 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2123 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2125 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2126 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2127 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2129 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2130 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2131 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2133 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2136 void PF_te_bloodshower (void)
2138 if (G_FLOAT(OFS_PARM3) < 1)
2140 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2141 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2143 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2144 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2145 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2147 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2148 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2149 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2151 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2153 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2156 void PF_te_explosionrgb (void)
2158 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2159 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2161 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2162 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2163 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2165 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2166 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2167 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2170 void PF_te_particlecube (void)
2172 if (G_FLOAT(OFS_PARM3) < 1)
2174 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2175 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2179 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2181 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2185 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2186 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2189 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2191 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2192 // gravity true/false
2193 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2195 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2198 void PF_te_particlerain (void)
2200 if (G_FLOAT(OFS_PARM3) < 1)
2202 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2203 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2205 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2206 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2207 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2209 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2213 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2217 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2219 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2222 void PF_te_particlesnow (void)
2224 if (G_FLOAT(OFS_PARM3) < 1)
2226 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2227 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2231 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2237 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2241 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2243 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2246 void PF_te_spark (void)
2248 if (G_FLOAT(OFS_PARM2) < 1)
2250 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2251 MSG_WriteByte(&sv.datagram, TE_SPARK);
2253 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2254 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2255 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2257 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2258 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2259 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2261 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2264 void PF_te_gunshotquad (void)
2266 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2267 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2269 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2270 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2271 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2274 void PF_te_spikequad (void)
2276 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2277 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2279 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2280 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2284 void PF_te_superspikequad (void)
2286 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2287 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2289 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2290 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2294 void PF_te_explosionquad (void)
2296 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2297 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2299 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2300 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2301 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2304 void PF_te_smallflash (void)
2306 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2307 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2309 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2310 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2314 void PF_te_customflash (void)
2316 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2318 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2319 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2321 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2322 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2323 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2325 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2327 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2329 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2330 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2331 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2334 void PF_te_gunshot (void)
2336 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2337 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2339 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2340 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2341 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2344 void PF_te_spike (void)
2346 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2347 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2349 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2350 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2354 void PF_te_superspike (void)
2356 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2357 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2359 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2360 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2364 void PF_te_explosion (void)
2366 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2367 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2369 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2370 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2374 void PF_te_tarexplosion (void)
2376 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2377 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2379 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2380 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2381 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2384 void PF_te_wizspike (void)
2386 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2387 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2389 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2390 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2394 void PF_te_knightspike (void)
2396 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2399 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2400 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2404 void PF_te_lavasplash (void)
2406 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2407 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2409 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2410 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2414 void PF_te_teleport (void)
2416 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2417 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2419 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2420 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2424 void PF_te_explosion2 (void)
2426 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2427 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2429 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2430 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2433 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2436 void PF_te_lightning1 (void)
2438 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2439 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2441 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2443 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2445 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2447 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2448 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2452 void PF_te_lightning2 (void)
2454 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2455 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2457 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2465 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2468 void PF_te_lightning3 (void)
2470 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2471 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2473 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2477 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2479 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2484 void PF_te_beam (void)
2486 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2487 MSG_WriteByte(&sv.datagram, TE_BEAM);
2489 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2500 void PF_te_plasmaburn (void)
2502 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2503 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2504 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2505 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2509 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2512 vec3_t v1, clipplanenormal, normal;
2513 vec_t clipplanedist, clipdist;
2515 if (surf->flags & SURF_PLANEBACK)
2516 VectorNegate(surf->plane->normal, normal);
2518 VectorCopy(surf->plane->normal, normal);
2519 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2521 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2522 VectorNormalizeFast(v1);
2523 CrossProduct(v1, normal, clipplanenormal);
2524 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2525 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2528 clipdist = -clipdist;
2529 VectorMA(out, clipdist, clipplanenormal, out);
2534 static msurface_t *getsurface(edict_t *ed, int surfnum)
2538 if (!ed || ed->e->free)
2540 modelindex = ed->v->modelindex;
2541 if (modelindex < 1 || modelindex >= MAX_MODELS)
2543 model = sv.models[modelindex];
2544 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2546 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2550 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2551 void PF_getsurfacenumpoints(void)
2554 // return 0 if no such surface
2555 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2557 G_FLOAT(OFS_RETURN) = 0;
2561 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2563 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2564 void PF_getsurfacepoint(void)
2569 VectorClear(G_VECTOR(OFS_RETURN));
2570 ed = G_EDICT(OFS_PARM0);
2571 if (!ed || ed->e->free)
2573 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2575 pointnum = G_FLOAT(OFS_PARM2);
2576 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2578 // FIXME: implement rotation/scaling
2579 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2581 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2582 void PF_getsurfacenormal(void)
2585 VectorClear(G_VECTOR(OFS_RETURN));
2586 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2588 // FIXME: implement rotation/scaling
2589 if (surf->flags & SURF_PLANEBACK)
2590 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2592 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2594 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2595 void PF_getsurfacetexture(void)
2598 G_INT(OFS_RETURN) = 0;
2599 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2601 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2603 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2604 void PF_getsurfacenearpoint(void)
2606 int surfnum, best, modelindex;
2608 vec_t dist, bestdist;
2613 G_FLOAT(OFS_RETURN) = -1;
2614 ed = G_EDICT(OFS_PARM0);
2615 point = G_VECTOR(OFS_PARM1);
2617 if (!ed || ed->e->free)
2619 modelindex = ed->v->modelindex;
2620 if (modelindex < 1 || modelindex >= MAX_MODELS)
2622 model = sv.models[modelindex];
2623 if (!model->brushq1.numsurfaces)
2626 // FIXME: implement rotation/scaling
2627 VectorSubtract(point, ed->v->origin, p);
2629 bestdist = 1000000000;
2630 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2632 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2633 dist = PlaneDiff(p, surf->plane);
2635 if (dist < bestdist)
2637 clippointtosurface(surf, p, clipped);
2638 VectorSubtract(clipped, p, clipped);
2639 dist += DotProduct(clipped, clipped);
2640 if (dist < bestdist)
2647 G_FLOAT(OFS_RETURN) = best;
2649 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2650 void PF_getsurfaceclippedpoint(void)
2655 VectorClear(G_VECTOR(OFS_RETURN));
2656 ed = G_EDICT(OFS_PARM0);
2657 if (!ed || ed->e->free)
2659 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2661 // FIXME: implement rotation/scaling
2662 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2663 clippointtosurface(surf, p, out);
2664 // FIXME: implement rotation/scaling
2665 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2668 #define MAX_PRFILES 256
2670 qfile_t *pr_files[MAX_PRFILES];
2672 void PR_Files_Init(void)
2674 memset(pr_files, 0, sizeof(pr_files));
2677 void PR_Files_CloseAll(void)
2680 for (i = 0;i < MAX_PRFILES;i++)
2683 FS_Close(pr_files[i]);
2688 //float(string s) stof = #81; // get numerical value from a string
2691 char string[STRINGTEMP_LENGTH];
2692 PF_VarString(0, string, sizeof(string));
2693 G_FLOAT(OFS_RETURN) = atof(string);
2696 //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
2700 char *modestring, *filename;
2701 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2702 if (pr_files[filenum] == NULL)
2704 if (filenum >= MAX_PRFILES)
2706 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2707 G_FLOAT(OFS_RETURN) = -2;
2710 mode = G_FLOAT(OFS_PARM1);
2713 case 0: // FILE_READ
2716 case 1: // FILE_APPEND
2719 case 2: // FILE_WRITE
2723 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2724 G_FLOAT(OFS_RETURN) = -3;
2727 filename = G_STRING(OFS_PARM0);
2728 // .. is parent directory on many platforms
2729 // / is parent directory on Amiga
2730 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2731 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2732 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2734 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2735 G_FLOAT(OFS_RETURN) = -4;
2738 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2739 if (pr_files[filenum] == NULL)
2740 G_FLOAT(OFS_RETURN) = -1;
2742 G_FLOAT(OFS_RETURN) = filenum;
2745 //void(float fhandle) fclose = #111; // closes a file
2746 void PF_fclose(void)
2748 int filenum = G_FLOAT(OFS_PARM0);
2749 if (filenum < 0 || filenum >= MAX_PRFILES)
2751 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2754 if (pr_files[filenum] == NULL)
2756 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2759 FS_Close(pr_files[filenum]);
2760 pr_files[filenum] = NULL;
2763 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2767 static char string[STRINGTEMP_LENGTH];
2768 int filenum = G_FLOAT(OFS_PARM0);
2769 if (filenum < 0 || filenum >= MAX_PRFILES)
2771 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2774 if (pr_files[filenum] == NULL)
2776 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2782 c = FS_Getc(pr_files[filenum]);
2783 if (c == '\r' || c == '\n' || c < 0)
2785 if (end < STRINGTEMP_LENGTH - 1)
2789 // remove \n following \r
2791 c = FS_Getc(pr_files[filenum]);
2792 if (developer.integer)
2793 Con_Printf("fgets: %s\n", string);
2795 G_INT(OFS_RETURN) = PR_SetString(string);
2797 G_INT(OFS_RETURN) = 0;
2800 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2804 char string[STRINGTEMP_LENGTH];
2805 int filenum = G_FLOAT(OFS_PARM0);
2806 if (filenum < 0 || filenum >= MAX_PRFILES)
2808 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2811 if (pr_files[filenum] == NULL)
2813 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2816 PF_VarString(1, string, sizeof(string));
2817 if ((stringlength = strlen(string)))
2818 FS_Write(pr_files[filenum], string, stringlength);
2819 if (developer.integer)
2820 Con_Printf("fputs: %s\n", string);
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 = PR_GetTempString();
2838 PF_VarString(0, s, STRINGTEMP_LENGTH);
2839 G_INT(OFS_RETURN) = PR_SetString(s);
2842 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2843 void PF_substring(void)
2845 int i, start, length;
2846 char *s, *string = PR_GetTempString();
2847 s = G_STRING(OFS_PARM0);
2848 start = G_FLOAT(OFS_PARM1);
2849 length = G_FLOAT(OFS_PARM2);
2852 for (i = 0;i < start && *s;i++, s++);
2853 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2856 G_INT(OFS_RETURN) = PR_SetString(string);
2859 //vector(string s) stov = #117; // returns vector value from a string
2862 char string[STRINGTEMP_LENGTH];
2863 PF_VarString(0, string, sizeof(string));
2864 Math_atov(string, G_VECTOR(OFS_RETURN));
2867 //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)
2868 void PF_strzone(void)
2871 in = G_STRING(OFS_PARM0);
2872 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2874 G_INT(OFS_RETURN) = PR_SetString(out);
2877 //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!!!)
2878 void PF_strunzone(void)
2880 Mem_Free(G_STRING(OFS_PARM0));
2883 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2884 //this function originally written by KrimZon, made shorter by LordHavoc
2885 void PF_clientcommand (void)
2887 client_t *temp_client;
2890 //find client for this entity
2891 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2892 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2894 Con_Printf("PF_clientcommand: entity is not a client");
2898 temp_client = host_client;
2899 host_client = svs.clients + i;
2900 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2901 host_client = temp_client;
2904 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2905 //this function originally written by KrimZon, made shorter by LordHavoc
2906 char **tokens = NULL;
2907 int max_tokens, num_tokens = 0;
2908 void PF_tokenize (void)
2912 str = G_STRING(OFS_PARM0);
2917 for (i=0;i<num_tokens;i++)
2923 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2924 max_tokens = strlen(str);
2926 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2928 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2929 strcpy(tokens[num_tokens], com_token);
2932 G_FLOAT(OFS_RETURN) = num_tokens;
2935 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2936 //this function originally written by KrimZon, made shorter by LordHavoc
2939 int token_num = G_FLOAT(OFS_PARM0);
2940 if (token_num >= 0 && token_num < num_tokens)
2941 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2943 G_INT(OFS_RETURN) = PR_SetString("");
2946 //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)
2947 void PF_setattachment (void)
2949 edict_t *e = G_EDICT(OFS_PARM0);
2950 edict_t *tagentity = G_EDICT(OFS_PARM1);
2951 char *tagname = G_STRING(OFS_PARM2);
2956 if (tagentity == NULL)
2957 tagentity = sv.edicts;
2959 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2961 v->edict = EDICT_TO_PROG(tagentity);
2963 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2966 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2968 modelindex = (int)tagentity->v->modelindex;
2969 if (modelindex >= 0 && modelindex < MAX_MODELS)
2971 model = sv.models[modelindex];
2972 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2973 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2974 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2976 if (v->_float == 0 && model->alias.aliasnum_tags)
2977 for (i = 0;i < model->alias.aliasnum_tags;i++)
2978 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2981 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);
2984 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));
2989 builtin_t pr_builtin[] =
2992 PF_makevectors, // #1 void(entity e) makevectors
2993 PF_setorigin, // #2 void(entity e, vector o) setorigin
2994 PF_setmodel, // #3 void(entity e, string m) setmodel
2995 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2996 NULL, // #5 void(entity e, vector min, vector max) setabssize
2997 PF_break, // #6 void() break
2998 PF_random, // #7 float() random
2999 PF_sound, // #8 void(entity e, float chan, string samp) sound
3000 PF_normalize, // #9 vector(vector v) normalize
3001 PF_error, // #10 void(string e) error
3002 PF_objerror, // #11 void(string e) objerror
3003 PF_vlen, // #12 float(vector v) vlen
3004 PF_vectoyaw, // #13 float(vector v) vectoyaw
3005 PF_Spawn, // #14 entity() spawn
3006 PF_Remove, // #15 void(entity e) remove
3007 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3008 PF_checkclient, // #17 entity() clientlist
3009 PF_Find, // #18 entity(entity start, .string fld, string match) find
3010 PF_precache_sound, // #19 void(string s) precache_sound
3011 PF_precache_model, // #20 void(string s) precache_model
3012 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3013 PF_findradius, // #22 entity(vector org, float rad) findradius
3014 PF_bprint, // #23 void(string s) bprint
3015 PF_sprint, // #24 void(entity client, string s) sprint
3016 PF_dprint, // #25 void(string s) dprint
3017 PF_ftos, // #26 void(string s) ftos
3018 PF_vtos, // #27 void(string s) vtos
3019 PF_coredump, // #28 void() coredump
3020 PF_traceon, // #29 void() traceon
3021 PF_traceoff, // #30 void() traceoff
3022 PF_eprint, // #31 void(entity e) eprint
3023 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3025 PF_droptofloor, // #34 float() droptofloor
3026 PF_lightstyle, // #35 void(float style, string value) lightstyle
3027 PF_rint, // #36 float(float v) rint
3028 PF_floor, // #37 float(float v) floor
3029 PF_ceil, // #38 float(float v) ceil
3031 PF_checkbottom, // #40 float(entity e) checkbottom
3032 PF_pointcontents , // #41 float(vector v) pointcontents
3034 PF_fabs, // #43 float(float f) fabs
3035 PF_aim, // #44 vector(entity e, float speed) aim
3036 PF_cvar, // #45 float(string s) cvar
3037 PF_localcmd, // #46 void(string s) localcmd
3038 PF_nextent, // #47 entity(entity e) nextent
3039 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3040 PF_changeyaw, // #49 void() ChangeYaw
3042 PF_vectoangles, // #51 vector(vector v) vectoangles
3043 PF_WriteByte, // #52 void(float to, float f) WriteByte
3044 PF_WriteChar, // #53 void(float to, float f) WriteChar
3045 PF_WriteShort, // #54 void(float to, float f) WriteShort
3046 PF_WriteLong, // #55 void(float to, float f) WriteLong
3047 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3048 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3049 PF_WriteString, // #58 void(float to, string s) WriteString
3050 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3051 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3052 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3053 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3054 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3055 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3056 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3058 SV_MoveToGoal, // #67 void(float step) movetogoal
3059 PF_precache_file, // #68 string(string s) precache_file
3060 PF_makestatic, // #69 void(entity e) makestatic
3061 PF_changelevel, // #70 void(string s) changelevel
3063 PF_cvar_set, // #72 void(string var, string val) cvar_set
3064 PF_centerprint, // #73 void(entity client, strings) centerprint
3065 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3066 PF_precache_model, // #75 string(string s) precache_model2
3067 PF_precache_sound, // #76 string(string s) precache_sound2
3068 PF_precache_file, // #77 string(string s) precache_file2
3069 PF_setspawnparms, // #78 void(entity e) setspawnparms
3072 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3081 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3082 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3083 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3084 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3085 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3086 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3087 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3088 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3089 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3090 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3101 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3102 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3103 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3104 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3105 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3106 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3107 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3108 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3109 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3110 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3111 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3112 a a a a a a a a // #120-199
3113 a a a a a a a a a a // #200-299
3114 a a a a a a a a a a // #300-399
3115 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3116 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3117 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3118 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3119 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3120 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3121 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3122 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3123 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3124 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3125 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3126 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3127 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3128 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3129 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3130 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3131 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3132 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3133 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3134 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3135 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3136 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3137 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3138 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3139 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3140 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3141 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3142 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3143 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3144 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3145 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3146 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3147 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3148 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3149 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3150 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3151 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3152 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3153 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3154 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3155 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3156 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3157 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3158 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3165 a a a a a // #450-499 (LordHavoc)
3168 builtin_t *pr_builtins = pr_builtin;
3169 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3171 void PR_Cmd_Init(void)
3173 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3177 void PR_Cmd_Reset(void)
3179 Mem_EmptyPool(pr_strings_mempool);
3180 PR_Files_CloseAll();