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)
377 Con_Printf ("tried to sprint to a non-client\n");
381 client = &svs.clients[entnum-1];
383 MSG_WriteChar (&client->message,svc_print);
384 MSG_WriteString (&client->message, s );
392 single print to a specific client
394 centerprint(clientent, value)
397 void PF_centerprint (void)
403 entnum = G_EDICTNUM(OFS_PARM0);
406 if (entnum < 1 || entnum > svs.maxclients)
408 Con_Printf ("tried to sprint to a non-client\n");
412 client = &svs.clients[entnum-1];
414 MSG_WriteChar (&client->message,svc_centerprint);
415 MSG_WriteString (&client->message, s );
423 vector normalize(vector)
426 void PF_normalize (void)
432 value1 = G_VECTOR(OFS_PARM0);
434 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
438 newvalue[0] = newvalue[1] = newvalue[2] = 0;
442 newvalue[0] = value1[0] * new;
443 newvalue[1] = value1[1] * new;
444 newvalue[2] = value1[2] * new;
447 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
462 value1 = G_VECTOR(OFS_PARM0);
464 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
467 G_FLOAT(OFS_RETURN) = new;
474 float vectoyaw(vector)
477 void PF_vectoyaw (void)
482 value1 = G_VECTOR(OFS_PARM0);
484 if (value1[1] == 0 && value1[0] == 0)
488 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
493 G_FLOAT(OFS_RETURN) = yaw;
501 vector vectoangles(vector)
504 void PF_vectoangles (void)
510 value1 = G_VECTOR(OFS_PARM0);
512 if (value1[1] == 0 && value1[0] == 0)
522 // LordHavoc: optimized a bit
525 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
529 else if (value1[1] > 0)
534 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
535 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
540 G_FLOAT(OFS_RETURN+0) = pitch;
541 G_FLOAT(OFS_RETURN+1) = yaw;
542 G_FLOAT(OFS_RETURN+2) = 0;
549 Returns a number from 0<= num < 1
554 void PF_random (void)
558 num = (rand ()&0x7fff) / ((float)0x7fff);
560 G_FLOAT(OFS_RETURN) = num;
567 particle(origin, color, count)
570 void PF_particle (void)
576 org = G_VECTOR(OFS_PARM0);
577 dir = G_VECTOR(OFS_PARM1);
578 color = G_FLOAT(OFS_PARM2);
579 count = G_FLOAT(OFS_PARM3);
580 SV_StartParticle (org, dir, color, count);
590 void PF_ambientsound (void)
595 float vol, attenuation;
596 int i, soundnum, large;
598 pos = G_VECTOR (OFS_PARM0);
599 samp = G_STRING(OFS_PARM1);
600 vol = G_FLOAT(OFS_PARM2);
601 attenuation = G_FLOAT(OFS_PARM3);
603 // check to see if samp was properly precached
604 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
605 if (!strcmp(*check,samp))
610 Con_Printf ("no precache: %s\n", samp);
618 // add an svc_spawnambient command to the level signon packet
621 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
623 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
625 for (i=0 ; i<3 ; i++)
626 MSG_WriteDPCoord(&sv.signon, pos[i]);
629 MSG_WriteShort (&sv.signon, soundnum);
631 MSG_WriteByte (&sv.signon, soundnum);
633 MSG_WriteByte (&sv.signon, vol*255);
634 MSG_WriteByte (&sv.signon, attenuation*64);
642 Each entity can have eight independant sound sources, like voice,
645 Channel 0 is an auto-allocate channel, the others override anything
646 already running on that entity/channel pair.
648 An attenuation of 0 will play full volume everywhere in the level.
649 Larger attenuations will drop off.
661 entity = G_EDICT(OFS_PARM0);
662 channel = G_FLOAT(OFS_PARM1);
663 sample = G_STRING(OFS_PARM2);
664 volume = G_FLOAT(OFS_PARM3) * 255;
665 attenuation = G_FLOAT(OFS_PARM4);
667 if (volume < 0 || volume > 255)
668 Host_Error ("SV_StartSound: volume = %i", volume);
670 if (attenuation < 0 || attenuation > 4)
671 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
673 if (channel < 0 || channel > 7)
674 Host_Error ("SV_StartSound: channel = %i", channel);
676 SV_StartSound (entity, channel, sample, volume, attenuation);
688 Host_Error ("break statement");
695 Used for use tracing and shot targeting
696 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
697 if the tryents flag is set.
699 traceline (vector1, vector2, tryents)
702 void PF_traceline (void)
709 pr_xfunction->builtinsprofile += 30;
711 v1 = G_VECTOR(OFS_PARM0);
712 v2 = G_VECTOR(OFS_PARM1);
713 nomonsters = G_FLOAT(OFS_PARM2);
714 ent = G_EDICT(OFS_PARM3);
716 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
718 pr_global_struct->trace_allsolid = trace.allsolid;
719 pr_global_struct->trace_startsolid = trace.startsolid;
720 pr_global_struct->trace_fraction = trace.fraction;
721 pr_global_struct->trace_inwater = trace.inwater;
722 pr_global_struct->trace_inopen = trace.inopen;
723 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
724 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
725 pr_global_struct->trace_plane_dist = trace.plane.dist;
727 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
729 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
730 // FIXME: add trace_endcontents
738 Used for use tracing and shot targeting
739 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
740 if the tryents flag is set.
742 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
745 // LordHavoc: added this for my own use, VERY useful, similar to traceline
746 void PF_tracebox (void)
748 float *v1, *v2, *m1, *m2;
753 pr_xfunction->builtinsprofile += 30;
755 v1 = G_VECTOR(OFS_PARM0);
756 m1 = G_VECTOR(OFS_PARM1);
757 m2 = G_VECTOR(OFS_PARM2);
758 v2 = G_VECTOR(OFS_PARM3);
759 nomonsters = G_FLOAT(OFS_PARM4);
760 ent = G_EDICT(OFS_PARM5);
762 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
764 pr_global_struct->trace_allsolid = trace.allsolid;
765 pr_global_struct->trace_startsolid = trace.startsolid;
766 pr_global_struct->trace_fraction = trace.fraction;
767 pr_global_struct->trace_inwater = trace.inwater;
768 pr_global_struct->trace_inopen = trace.inopen;
769 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
770 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
771 pr_global_struct->trace_plane_dist = trace.plane.dist;
773 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
775 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
778 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
779 void PF_TraceToss (void)
785 pr_xfunction->builtinsprofile += 600;
787 ent = G_EDICT(OFS_PARM0);
788 ignore = G_EDICT(OFS_PARM1);
790 trace = SV_Trace_Toss (ent, ignore);
792 pr_global_struct->trace_allsolid = trace.allsolid;
793 pr_global_struct->trace_startsolid = trace.startsolid;
794 pr_global_struct->trace_fraction = trace.fraction;
795 pr_global_struct->trace_inwater = trace.inwater;
796 pr_global_struct->trace_inopen = trace.inopen;
797 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
798 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
799 pr_global_struct->trace_plane_dist = trace.plane.dist;
801 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
803 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
811 Returns true if the given entity can move to the given position from it's
812 current position by walking or rolling.
814 scalar checkpos (entity, vector)
817 void PF_checkpos (void)
821 //============================================================================
823 qbyte checkpvs[MAX_MAP_LEAFS/8];
825 int PF_newcheckclient (int check)
831 // cycle to the next one
835 if (check > svs.maxclients)
836 check = svs.maxclients;
838 if (check == svs.maxclients)
845 pr_xfunction->builtinsprofile++;
846 if (i == svs.maxclients+1)
852 break; // didn't find anything else
856 if (ent->v->health <= 0)
858 if ((int)ent->v->flags & FL_NOTARGET)
861 // anything that is a client, or has a client as an enemy
865 // get the PVS for the entity
866 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
867 memcpy (checkpvs, sv.worldmodel->brushq1.LeafPVS(sv.worldmodel, sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, org)), (sv.worldmodel->brushq1.numleafs+7)>>3 );
876 Returns a client (or object that has a client enemy) that would be a
879 If there is more than one valid option, they are cycled each frame
881 If (self.origin + self.viewofs) is not in the PVS of the current target,
882 it is not returned at all.
887 int c_invis, c_notvis;
888 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 leaf = sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, view);
916 l = (leaf - sv.worldmodel->brushq1.leafs) - 1;
917 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
920 RETURN_EDICT(sv.edicts);
925 // might be able to see it
930 //============================================================================
937 Sends text over to the client's execution buffer
939 stuffcmd (clientent, value)
942 void PF_stuffcmd (void)
948 entnum = G_EDICTNUM(OFS_PARM0);
949 if (entnum < 1 || entnum > svs.maxclients)
950 Host_Error ("Parm 0 not a client");
951 str = G_STRING(OFS_PARM1);
954 host_client = &svs.clients[entnum-1];
955 Host_ClientCommands ("%s", str);
963 Sends text over to the client's execution buffer
968 void PF_localcmd (void)
972 str = G_STRING(OFS_PARM0);
987 str = G_STRING(OFS_PARM0);
989 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
999 void PF_cvar_set (void)
1003 var = G_STRING(OFS_PARM0);
1004 val = G_STRING(OFS_PARM1);
1006 Cvar_Set (var, val);
1013 Returns a chain of entities that have origins within a spherical area
1015 findradius (origin, radius)
1018 void PF_findradius (void)
1020 edict_t *ent, *chain;
1027 chain = (edict_t *)sv.edicts;
1029 org = G_VECTOR(OFS_PARM0);
1030 radius = G_FLOAT(OFS_PARM1);
1031 radius2 = radius * radius;
1033 ent = NEXT_EDICT(sv.edicts);
1034 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1036 pr_xfunction->builtinsprofile++;
1039 if (ent->v->solid == SOLID_NOT)
1042 // LordHavoc: compare against bounding box rather than center,
1043 // and use DotProduct instead of Length, major speedup
1044 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1045 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1046 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1047 if (DotProduct(eorg, eorg) > radius2)
1050 ent->v->chain = EDICT_TO_PROG(chain);
1054 RETURN_EDICT(chain);
1063 void PF_dprint (void)
1065 Con_DPrintf ("%s",PF_VarString(0));
1068 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1069 #define STRINGTEMP_BUFFERS 16
1070 #define STRINGTEMP_LENGTH 128
1071 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1072 static int pr_string_tempindex = 0;
1074 static char *PR_GetTempString(void)
1077 s = pr_string_temp[pr_string_tempindex];
1078 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1086 v = G_FLOAT(OFS_PARM0);
1088 s = PR_GetTempString();
1089 // LordHavoc: ftos improvement
1090 sprintf (s, "%g", v);
1091 G_INT(OFS_RETURN) = PR_SetString(s);
1097 v = G_FLOAT(OFS_PARM0);
1098 G_FLOAT(OFS_RETURN) = fabs(v);
1104 s = PR_GetTempString();
1105 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1106 G_INT(OFS_RETURN) = PR_SetString(s);
1112 s = PR_GetTempString();
1113 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1114 G_INT(OFS_RETURN) = PR_SetString(s);
1117 void PF_Spawn (void)
1120 pr_xfunction->builtinsprofile += 20;
1125 void PF_Remove (void)
1128 pr_xfunction->builtinsprofile += 20;
1130 ed = G_EDICT(OFS_PARM0);
1131 if (ed == sv.edicts)
1132 Host_Error("remove: tried to remove world\n");
1133 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1134 Host_Error("remove: tried to remove a client\n");
1139 // entity (entity start, .string field, string match) find = #5;
1147 e = G_EDICTNUM(OFS_PARM0);
1148 f = G_INT(OFS_PARM1);
1149 s = G_STRING(OFS_PARM2);
1152 RETURN_EDICT(sv.edicts);
1156 for (e++ ; e < sv.num_edicts ; e++)
1158 pr_xfunction->builtinsprofile++;
1172 RETURN_EDICT(sv.edicts);
1175 // LordHavoc: added this for searching float, int, and entity reference fields
1176 void PF_FindFloat (void)
1183 e = G_EDICTNUM(OFS_PARM0);
1184 f = G_INT(OFS_PARM1);
1185 s = G_FLOAT(OFS_PARM2);
1187 for (e++ ; e < sv.num_edicts ; e++)
1189 pr_xfunction->builtinsprofile++;
1193 if (E_FLOAT(ed,f) == s)
1200 RETURN_EDICT(sv.edicts);
1203 // chained search for strings in entity fields
1204 // entity(.string field, string match) findchain = #402;
1205 void PF_findchain (void)
1210 edict_t *ent, *chain;
1212 chain = (edict_t *)sv.edicts;
1214 f = G_INT(OFS_PARM0);
1215 s = G_STRING(OFS_PARM1);
1218 RETURN_EDICT(sv.edicts);
1222 ent = NEXT_EDICT(sv.edicts);
1223 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1225 pr_xfunction->builtinsprofile++;
1228 t = E_STRING(ent,f);
1234 ent->v->chain = EDICT_TO_PROG(chain);
1238 RETURN_EDICT(chain);
1241 // LordHavoc: chained search for float, int, and entity reference fields
1242 // entity(.string field, float match) findchainfloat = #403;
1243 void PF_findchainfloat (void)
1248 edict_t *ent, *chain;
1250 chain = (edict_t *)sv.edicts;
1252 f = G_INT(OFS_PARM0);
1253 s = G_FLOAT(OFS_PARM1);
1255 ent = NEXT_EDICT(sv.edicts);
1256 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1258 pr_xfunction->builtinsprofile++;
1261 if (E_FLOAT(ent,f) != s)
1264 ent->v->chain = EDICT_TO_PROG(chain);
1268 RETURN_EDICT(chain);
1271 void PR_CheckEmptyString (char *s)
1274 Host_Error ("Bad string");
1277 void PF_precache_file (void)
1278 { // precache_file is only used to copy files with qcc, it does nothing
1279 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1282 void PF_precache_sound (void)
1287 if (sv.state != ss_loading)
1288 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1290 s = G_STRING(OFS_PARM0);
1291 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1292 PR_CheckEmptyString (s);
1294 for (i=0 ; i<MAX_SOUNDS ; i++)
1296 if (!sv.sound_precache[i])
1298 sv.sound_precache[i] = s;
1301 if (!strcmp(sv.sound_precache[i], s))
1304 Host_Error ("PF_precache_sound: overflow");
1307 void PF_precache_model (void)
1312 if (sv.state != ss_loading)
1313 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1315 s = G_STRING(OFS_PARM0);
1316 if (sv.worldmodel->brushq1.ishlbsp && ((!s) || (!s[0])))
1318 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1319 PR_CheckEmptyString (s);
1321 for (i=0 ; i<MAX_MODELS ; i++)
1323 if (!sv.model_precache[i])
1325 sv.model_precache[i] = s;
1326 sv.models[i] = Mod_ForName (s, true, false, false);
1329 if (!strcmp(sv.model_precache[i], s))
1332 Host_Error ("PF_precache_model: overflow");
1336 void PF_coredump (void)
1341 void PF_traceon (void)
1346 void PF_traceoff (void)
1351 void PF_eprint (void)
1353 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1360 float(float yaw, float dist) walkmove
1363 void PF_walkmove (void)
1371 ent = PROG_TO_EDICT(pr_global_struct->self);
1372 yaw = G_FLOAT(OFS_PARM0);
1373 dist = G_FLOAT(OFS_PARM1);
1375 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1377 G_FLOAT(OFS_RETURN) = 0;
1381 yaw = yaw*M_PI*2 / 360;
1383 move[0] = cos(yaw)*dist;
1384 move[1] = sin(yaw)*dist;
1387 // save program state, because SV_movestep may call other progs
1388 oldf = pr_xfunction;
1389 oldself = pr_global_struct->self;
1391 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1394 // restore program state
1395 pr_xfunction = oldf;
1396 pr_global_struct->self = oldself;
1406 void PF_droptofloor (void)
1412 ent = PROG_TO_EDICT(pr_global_struct->self);
1414 VectorCopy (ent->v->origin, end);
1417 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1419 if (trace.fraction == 1)
1420 G_FLOAT(OFS_RETURN) = 0;
1423 VectorCopy (trace.endpos, ent->v->origin);
1424 SV_LinkEdict (ent, false);
1425 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1426 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1427 G_FLOAT(OFS_RETURN) = 1;
1428 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1429 ent->e->suspendedinairflag = true;
1437 void(float style, string value) lightstyle
1440 void PF_lightstyle (void)
1447 style = G_FLOAT(OFS_PARM0);
1448 val = G_STRING(OFS_PARM1);
1450 // change the string in sv
1451 sv.lightstyles[style] = val;
1453 // send message to all clients on this server
1454 if (sv.state != ss_active)
1457 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1458 if (client->active || client->spawned)
1460 MSG_WriteChar (&client->message, svc_lightstyle);
1461 MSG_WriteChar (&client->message,style);
1462 MSG_WriteString (&client->message, val);
1469 f = G_FLOAT(OFS_PARM0);
1471 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1473 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1475 void PF_floor (void)
1477 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1481 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1490 void PF_checkbottom (void)
1492 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1500 void PF_pointcontents (void)
1502 G_FLOAT(OFS_RETURN) = SV_PointContents(G_VECTOR(OFS_PARM0));
1509 entity nextent(entity)
1512 void PF_nextent (void)
1517 i = G_EDICTNUM(OFS_PARM0);
1520 pr_xfunction->builtinsprofile++;
1522 if (i == sv.num_edicts)
1524 RETURN_EDICT(sv.edicts);
1540 Pick a vector for the player to shoot along
1541 vector aim(entity, missilespeed)
1546 edict_t *ent, *check, *bestent;
1547 vec3_t start, dir, end, bestdir;
1550 float dist, bestdist;
1553 ent = G_EDICT(OFS_PARM0);
1554 speed = G_FLOAT(OFS_PARM1);
1556 VectorCopy (ent->v->origin, start);
1559 // try sending a trace straight
1560 VectorCopy (pr_global_struct->v_forward, dir);
1561 VectorMA (start, 2048, dir, end);
1562 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1563 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1564 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1566 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1571 // try all possible entities
1572 VectorCopy (dir, bestdir);
1573 bestdist = sv_aim.value;
1576 check = NEXT_EDICT(sv.edicts);
1577 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1579 pr_xfunction->builtinsprofile++;
1580 if (check->v->takedamage != DAMAGE_AIM)
1584 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1585 continue; // don't aim at teammate
1586 for (j=0 ; j<3 ; j++)
1587 end[j] = check->v->origin[j]
1588 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1589 VectorSubtract (end, start, dir);
1590 VectorNormalize (dir);
1591 dist = DotProduct (dir, pr_global_struct->v_forward);
1592 if (dist < bestdist)
1593 continue; // to far to turn
1594 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1595 if (tr.ent == check)
1596 { // can shoot at this one
1604 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1605 dist = DotProduct (dir, pr_global_struct->v_forward);
1606 VectorScale (pr_global_struct->v_forward, dist, end);
1608 VectorNormalize (end);
1609 VectorCopy (end, G_VECTOR(OFS_RETURN));
1613 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1621 This was a major timewaster in progs, so it was converted to C
1624 void PF_changeyaw (void)
1627 float ideal, current, move, speed;
1629 ent = PROG_TO_EDICT(pr_global_struct->self);
1630 current = ANGLEMOD(ent->v->angles[1]);
1631 ideal = ent->v->ideal_yaw;
1632 speed = ent->v->yaw_speed;
1634 if (current == ideal)
1636 move = ideal - current;
1637 if (ideal > current)
1658 ent->v->angles[1] = ANGLEMOD (current + move);
1666 void PF_changepitch (void)
1669 float ideal, current, move, speed;
1672 ent = G_EDICT(OFS_PARM0);
1673 current = ANGLEMOD( ent->v->angles[0] );
1674 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1675 ideal = val->_float;
1678 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1681 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1682 speed = val->_float;
1685 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1689 if (current == ideal)
1691 move = ideal - current;
1692 if (ideal > current)
1713 ent->v->angles[0] = ANGLEMOD (current + move);
1717 ===============================================================================
1721 ===============================================================================
1724 #define MSG_BROADCAST 0 // unreliable to all
1725 #define MSG_ONE 1 // reliable to one (msg_entity)
1726 #define MSG_ALL 2 // reliable to all
1727 #define MSG_INIT 3 // write to the init string
1729 sizebuf_t *WriteDest (void)
1735 dest = G_FLOAT(OFS_PARM0);
1739 return &sv.datagram;
1742 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1743 entnum = NUM_FOR_EDICT(ent);
1744 if (entnum < 1 || entnum > svs.maxclients)
1745 Host_Error ("WriteDest: not a client");
1746 return &svs.clients[entnum-1].message;
1749 return &sv.reliable_datagram;
1755 Host_Error ("WriteDest: bad destination");
1762 void PF_WriteByte (void)
1764 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1767 void PF_WriteChar (void)
1769 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1772 void PF_WriteShort (void)
1774 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1777 void PF_WriteLong (void)
1779 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1782 void PF_WriteAngle (void)
1784 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1787 void PF_WriteCoord (void)
1789 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1792 void PF_WriteString (void)
1794 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1798 void PF_WriteEntity (void)
1800 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1803 //=============================================================================
1805 void PF_makestatic (void)
1810 ent = G_EDICT(OFS_PARM0);
1813 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1818 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1819 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1820 MSG_WriteShort (&sv.signon, ent->v->frame);
1824 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1825 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1826 MSG_WriteByte (&sv.signon, ent->v->frame);
1829 MSG_WriteByte (&sv.signon, ent->v->colormap);
1830 MSG_WriteByte (&sv.signon, ent->v->skin);
1831 for (i=0 ; i<3 ; i++)
1833 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1834 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1837 // throw the entity away now
1841 //=============================================================================
1848 void PF_setspawnparms (void)
1854 ent = G_EDICT(OFS_PARM0);
1855 i = NUM_FOR_EDICT(ent);
1856 if (i < 1 || i > svs.maxclients)
1857 Host_Error ("Entity is not a client");
1859 // copy spawn parms out of the client_t
1860 client = svs.clients + (i-1);
1862 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1863 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1871 void PF_changelevel (void)
1875 // make sure we don't issue two changelevels
1876 if (svs.changelevel_issued)
1878 svs.changelevel_issued = true;
1880 s = G_STRING(OFS_PARM0);
1881 Cbuf_AddText (va("changelevel %s\n",s));
1886 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1891 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1896 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1903 Returns a vector of length < 1
1908 void PF_randomvec (void)
1913 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1914 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1915 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1917 while (DotProduct(temp, temp) >= 1);
1918 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1921 void SV_LightPoint (vec3_t color, vec3_t p);
1926 Returns a color vector indicating the lighting at the requested point.
1928 (Internal Operation note: actually measures the light beneath the point, just like
1929 the model lighting on the client)
1934 void PF_GetLight (void)
1938 p = G_VECTOR(OFS_PARM0);
1939 SV_LightPoint (color, p);
1940 VectorCopy (color, G_VECTOR(OFS_RETURN));
1943 #define MAX_QC_CVARS 128
1944 cvar_t qc_cvar[MAX_QC_CVARS];
1947 void PF_registercvar (void)
1951 name = G_STRING(OFS_PARM0);
1952 value = G_STRING(OFS_PARM1);
1953 G_FLOAT(OFS_RETURN) = 0;
1954 // first check to see if it has already been defined
1955 if (Cvar_FindVar (name))
1958 // check for overlap with a command
1959 if (Cmd_Exists (name))
1961 Con_Printf ("PF_registercvar: %s is a command\n", name);
1965 if (currentqc_cvar >= MAX_QC_CVARS)
1966 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1968 // copy the name and value
1969 variable = &qc_cvar[currentqc_cvar++];
1970 variable->name = Z_Malloc (strlen(name)+1);
1971 strcpy (variable->name, name);
1972 variable->string = Z_Malloc (strlen(value)+1);
1973 strcpy (variable->string, value);
1974 variable->value = atof (value);
1976 Cvar_RegisterVariable(variable);
1977 G_FLOAT(OFS_RETURN) = 1; // success
1984 returns the minimum of two supplied floats
1991 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1993 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1994 else if (pr_argc >= 3)
1997 float f = G_FLOAT(OFS_PARM0);
1998 for (i = 1;i < pr_argc;i++)
1999 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2000 f = G_FLOAT((OFS_PARM0+i*3));
2001 G_FLOAT(OFS_RETURN) = f;
2004 Host_Error("min: must supply at least 2 floats\n");
2011 returns the maximum of two supplied floats
2018 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2020 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2021 else if (pr_argc >= 3)
2024 float f = G_FLOAT(OFS_PARM0);
2025 for (i = 1;i < pr_argc;i++)
2026 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2027 f = G_FLOAT((OFS_PARM0+i*3));
2028 G_FLOAT(OFS_RETURN) = f;
2031 Host_Error("max: must supply at least 2 floats\n");
2038 returns number bounded by supplied range
2040 min(min, value, max)
2043 void PF_bound (void)
2045 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2052 returns a raised to power b
2059 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2066 copies data from one entity to another
2068 copyentity(src, dst)
2071 void PF_copyentity (void)
2074 in = G_EDICT(OFS_PARM0);
2075 out = G_EDICT(OFS_PARM1);
2076 memcpy(out->v, in->v, progs->entityfields * 4);
2083 sets the color of a client and broadcasts the update to all connected clients
2085 setcolor(clientent, value)
2088 void PF_setcolor (void)
2094 entnum = G_EDICTNUM(OFS_PARM0);
2095 i = G_FLOAT(OFS_PARM1);
2097 if (entnum < 1 || entnum > svs.maxclients)
2099 Con_Printf ("tried to setcolor a non-client\n");
2103 client = &svs.clients[entnum-1];
2104 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2107 client->old_colors = i;
2108 client->edict->v->team = (i & 15) + 1;
2110 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2111 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2112 MSG_WriteByte (&sv.reliable_datagram, i);
2119 effect(origin, modelname, startframe, framecount, framerate)
2122 void PF_effect (void)
2125 s = G_STRING(OFS_PARM1);
2127 Host_Error("effect: no model specified\n");
2129 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2132 void PF_te_blood (void)
2134 if (G_FLOAT(OFS_PARM2) < 1)
2136 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2137 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2139 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2140 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2141 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2143 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2144 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2145 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2147 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2150 void PF_te_bloodshower (void)
2152 if (G_FLOAT(OFS_PARM3) < 1)
2154 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2155 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2157 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2158 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2159 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2161 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2162 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2163 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2165 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2167 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2170 void PF_te_explosionrgb (void)
2172 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2173 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2175 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2176 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2179 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2180 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2181 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2184 void PF_te_particlecube (void)
2186 if (G_FLOAT(OFS_PARM3) < 1)
2188 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2189 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2191 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2192 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2193 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2195 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2196 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2197 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2199 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2200 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2201 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2203 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2205 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2206 // gravity true/false
2207 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2209 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2212 void PF_te_particlerain (void)
2214 if (G_FLOAT(OFS_PARM3) < 1)
2216 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2217 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2219 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2220 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2221 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2223 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2224 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2225 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2227 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2228 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2231 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2233 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2236 void PF_te_particlesnow (void)
2238 if (G_FLOAT(OFS_PARM3) < 1)
2240 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2241 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2243 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2244 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2245 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2247 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2248 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2249 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2251 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2252 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2253 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2255 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2257 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2260 void PF_te_spark (void)
2262 if (G_FLOAT(OFS_PARM2) < 1)
2264 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2265 MSG_WriteByte(&sv.datagram, TE_SPARK);
2267 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2268 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2269 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2271 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2272 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2273 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2275 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2278 void PF_te_gunshotquad (void)
2280 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2281 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2288 void PF_te_spikequad (void)
2290 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2291 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2293 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2294 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2295 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2298 void PF_te_superspikequad (void)
2300 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2301 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2303 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2308 void PF_te_explosionquad (void)
2310 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2311 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2313 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2314 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2315 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2318 void PF_te_smallflash (void)
2320 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2321 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
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]);
2328 void PF_te_customflash (void)
2330 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2332 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2333 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2335 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2336 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2337 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2339 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2341 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2343 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2344 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2345 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2348 void PF_te_gunshot (void)
2350 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2351 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2353 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2354 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2355 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2358 void PF_te_spike (void)
2360 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2361 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2363 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2364 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2365 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2368 void PF_te_superspike (void)
2370 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2371 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2375 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2378 void PF_te_explosion (void)
2380 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2381 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2383 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2384 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2385 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2388 void PF_te_tarexplosion (void)
2390 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2391 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2393 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2394 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2395 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2398 void PF_te_wizspike (void)
2400 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2401 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2403 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2404 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2405 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2408 void PF_te_knightspike (void)
2410 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2411 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2413 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2414 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2415 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2418 void PF_te_lavasplash (void)
2420 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2421 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2423 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2424 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2425 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2428 void PF_te_teleport (void)
2430 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2431 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2433 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2434 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2435 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2438 void PF_te_explosion2 (void)
2440 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2441 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2443 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2445 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2447 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2450 void PF_te_lightning1 (void)
2452 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2453 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2455 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2457 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2458 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2466 void PF_te_lightning2 (void)
2468 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2469 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2471 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2473 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2474 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2477 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2478 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2479 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2482 void PF_te_lightning3 (void)
2484 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2485 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2487 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2489 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2490 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2498 void PF_te_beam (void)
2500 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2501 MSG_WriteByte(&sv.datagram, TE_BEAM);
2503 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2505 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2509 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2510 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2511 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2514 void PF_te_plasmaburn (void)
2516 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2517 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2518 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2519 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2520 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2523 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2526 vec3_t v1, clipplanenormal, normal;
2527 vec_t clipplanedist, clipdist;
2529 if (surf->flags & SURF_PLANEBACK)
2530 VectorNegate(surf->plane->normal, normal);
2532 VectorCopy(surf->plane->normal, normal);
2533 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2535 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2536 VectorNormalizeFast(v1);
2537 CrossProduct(v1, normal, clipplanenormal);
2538 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2539 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2542 clipdist = -clipdist;
2543 VectorMA(out, clipdist, clipplanenormal, out);
2548 static msurface_t *getsurface(edict_t *ed, int surfnum)
2552 if (!ed || ed->e->free)
2554 modelindex = ed->v->modelindex;
2555 if (modelindex < 1 || modelindex >= MAX_MODELS)
2557 model = sv.models[modelindex];
2558 if (model->type != mod_brush)
2560 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2562 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2566 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2567 void PF_getsurfacenumpoints(void)
2570 // return 0 if no such surface
2571 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2573 G_FLOAT(OFS_RETURN) = 0;
2577 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2579 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2580 void PF_getsurfacepoint(void)
2585 VectorClear(G_VECTOR(OFS_RETURN));
2586 ed = G_EDICT(OFS_PARM0);
2587 if (!ed || ed->e->free)
2589 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2591 pointnum = G_FLOAT(OFS_PARM2);
2592 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2594 // FIXME: implement rotation/scaling
2595 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2597 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2598 void PF_getsurfacenormal(void)
2601 VectorClear(G_VECTOR(OFS_RETURN));
2602 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2604 // FIXME: implement rotation/scaling
2605 if (surf->flags & SURF_PLANEBACK)
2606 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2608 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2610 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2611 void PF_getsurfacetexture(void)
2614 G_INT(OFS_RETURN) = 0;
2615 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2617 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2619 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2620 void PF_getsurfacenearpoint(void)
2622 int surfnum, best, modelindex;
2624 vec_t dist, bestdist;
2629 G_FLOAT(OFS_RETURN) = -1;
2630 ed = G_EDICT(OFS_PARM0);
2631 point = G_VECTOR(OFS_PARM1);
2633 if (!ed || ed->e->free)
2635 modelindex = ed->v->modelindex;
2636 if (modelindex < 1 || modelindex >= MAX_MODELS)
2638 model = sv.models[modelindex];
2639 if (model->type != mod_brush)
2642 // FIXME: implement rotation/scaling
2643 VectorSubtract(point, ed->v->origin, p);
2645 bestdist = 1000000000;
2646 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2648 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2649 dist = PlaneDiff(p, surf->plane);
2651 if (dist < bestdist)
2653 clippointtosurface(surf, p, clipped);
2654 VectorSubtract(clipped, p, clipped);
2655 dist += DotProduct(clipped, clipped);
2656 if (dist < bestdist)
2663 G_FLOAT(OFS_RETURN) = best;
2665 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2666 void PF_getsurfaceclippedpoint(void)
2671 VectorClear(G_VECTOR(OFS_RETURN));
2672 ed = G_EDICT(OFS_PARM0);
2673 if (!ed || ed->e->free)
2675 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2677 // FIXME: implement rotation/scaling
2678 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2679 clippointtosurface(surf, p, out);
2680 // FIXME: implement rotation/scaling
2681 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2684 #define MAX_PRFILES 256
2686 qfile_t *pr_files[MAX_PRFILES];
2688 void PR_Files_Init(void)
2690 memset(pr_files, 0, sizeof(pr_files));
2693 void PR_Files_CloseAll(void)
2696 for (i = 0;i < MAX_PRFILES;i++)
2699 FS_Close(pr_files[i]);
2704 //float(string s) stof = #81; // get numerical value from a string
2707 char *s = PF_VarString(0);
2708 G_FLOAT(OFS_RETURN) = atof(s);
2711 //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
2715 char *modestring, *filename;
2716 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2717 if (pr_files[filenum] == NULL)
2719 if (filenum >= MAX_PRFILES)
2721 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2722 G_FLOAT(OFS_RETURN) = -2;
2725 mode = G_FLOAT(OFS_PARM1);
2728 case 0: // FILE_READ
2731 case 1: // FILE_APPEND
2734 case 2: // FILE_WRITE
2738 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2739 G_FLOAT(OFS_RETURN) = -3;
2742 filename = G_STRING(OFS_PARM0);
2743 // .. is parent directory on many platforms
2744 // / is parent directory on Amiga
2745 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2746 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2747 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2749 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2750 G_FLOAT(OFS_RETURN) = -4;
2753 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2754 if (pr_files[filenum] == NULL)
2755 G_FLOAT(OFS_RETURN) = -1;
2757 G_FLOAT(OFS_RETURN) = filenum;
2760 //void(float fhandle) fclose = #111; // closes a file
2761 void PF_fclose(void)
2763 int filenum = G_FLOAT(OFS_PARM0);
2764 if (filenum < 0 || filenum >= MAX_PRFILES)
2766 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2769 if (pr_files[filenum] == NULL)
2771 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2774 FS_Close(pr_files[filenum]);
2775 pr_files[filenum] = NULL;
2778 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2782 static char string[MAX_VARSTRING];
2783 int filenum = G_FLOAT(OFS_PARM0);
2784 if (filenum < 0 || filenum >= MAX_PRFILES)
2786 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2789 if (pr_files[filenum] == NULL)
2791 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2797 c = FS_Getc(pr_files[filenum]);
2798 if (c == '\r' || c == '\n' || c < 0)
2800 if (end < MAX_VARSTRING - 1)
2804 // remove \n following \r
2806 c = FS_Getc(pr_files[filenum]);
2807 if (developer.integer)
2808 Con_Printf("fgets: %s\n", string);
2810 G_INT(OFS_RETURN) = PR_SetString(string);
2812 G_INT(OFS_RETURN) = 0;
2815 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2819 char *s = PF_VarString(1);
2820 int filenum = G_FLOAT(OFS_PARM0);
2821 if (filenum < 0 || filenum >= MAX_PRFILES)
2823 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2826 if (pr_files[filenum] == NULL)
2828 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2831 if ((stringlength = strlen(s)))
2832 FS_Write(pr_files[filenum], s, stringlength);
2833 if (developer.integer)
2834 Con_Printf("fputs: %s\n", s);
2837 //float(string s) strlen = #114; // returns how many characters are in a string
2838 void PF_strlen(void)
2841 s = G_STRING(OFS_PARM0);
2843 G_FLOAT(OFS_RETURN) = strlen(s);
2845 G_FLOAT(OFS_RETURN) = 0;
2848 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2849 void PF_strcat(void)
2851 char *s = PF_VarString(0);
2852 G_INT(OFS_RETURN) = PR_SetString(s);
2855 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2856 void PF_substring(void)
2859 char *s, string[MAX_VARSTRING];
2860 s = G_STRING(OFS_PARM0);
2861 start = G_FLOAT(OFS_PARM1);
2862 end = G_FLOAT(OFS_PARM2) + start;
2865 for (i = 0;i < start && *s;i++, s++);
2866 for (i = 0;i < MAX_VARSTRING - 1 && *s && i < end;i++, s++)
2869 G_INT(OFS_RETURN) = PR_SetString(string);
2872 //vector(string s) stov = #117; // returns vector value from a string
2875 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2878 //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)
2879 void PF_strzone(void)
2882 in = G_STRING(OFS_PARM0);
2883 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2885 G_INT(OFS_RETURN) = PR_SetString(out);
2888 //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!!!)
2889 void PF_strunzone(void)
2891 Mem_Free(G_STRING(OFS_PARM0));
2894 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2895 //this function originally written by KrimZon, made shorter by LordHavoc
2896 void PF_clientcommand (void)
2898 client_t *temp_client;
2901 //find client for this entity
2902 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2903 if (i < 0 || i >= svs.maxclients)
2904 Host_Error("PF_clientcommand: entity is not a client");
2906 temp_client = host_client;
2907 host_client = &svs.clients[i];
2908 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2909 host_client = temp_client;
2912 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2913 //this function originally written by KrimZon, made shorter by LordHavoc
2914 char **tokens = NULL;
2915 int max_tokens, num_tokens = 0;
2916 void PF_tokenize (void)
2920 str = G_STRING(OFS_PARM0);
2925 for (i=0;i<num_tokens;i++)
2931 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2932 max_tokens = strlen(str);
2934 for (p = str;COM_ParseToken(&p) && num_tokens < max_tokens;num_tokens++)
2936 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2937 strcpy(tokens[num_tokens], com_token);
2940 G_FLOAT(OFS_RETURN) = num_tokens;
2943 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2944 //this function originally written by KrimZon, made shorter by LordHavoc
2947 int token_num = G_FLOAT(OFS_PARM0);
2948 if (token_num >= 0 && token_num < num_tokens)
2949 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2951 G_INT(OFS_RETURN) = PR_SetString("");
2954 //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)
2955 void PF_setattachment (void)
2957 edict_t *e = G_EDICT(OFS_PARM0);
2958 edict_t *tagentity = G_EDICT(OFS_PARM1);
2959 char *tagname = G_STRING(OFS_PARM2);
2964 if (tagentity == NULL)
2965 tagentity = sv.edicts;
2967 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2969 v->edict = EDICT_TO_PROG(tagentity);
2971 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2974 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2976 modelindex = (int)tagentity->v->modelindex;
2977 if (modelindex >= 0 && modelindex < MAX_MODELS)
2979 model = sv.models[modelindex];
2980 if (model->alias.aliasnum_tags)
2981 for (i = 0;i < model->alias.aliasnum_tags;i++)
2982 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
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();