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 for (i = first;i < pr_argc;i++)
52 // LordHavoc: FIXME: this is just a strlcat inlined
53 s = G_STRING((OFS_PARM0+i*3));
55 if (j > MAX_VARSTRING - 1 - end)
56 j = MAX_VARSTRING - 1 - end;
59 memcpy(pr_varstring_temp + end, s, j);
63 pr_varstring_temp[end] = 0;
64 return pr_varstring_temp;
67 char *ENGINE_EXTENSIONS =
76 "DP_ENT_CUSTOMCOLORMAP "
77 "DP_ENT_EXTERIORMODELTOCLIENT "
78 "DP_ENT_LOWPRECISION "
86 "DP_MOVETYPEBOUNCEMISSILE "
92 "DP_QC_FINDCHAINFLOAT "
98 "DP_QC_SINCOSSQRTPOW "
101 "DP_QC_VECTORVECTORS "
107 "DP_SV_DRAWONLYTOCLIENT "
109 "DP_SV_EXTERIORMODELTOCLIENT "
110 "DP_SV_NODRAWTOCLIENT "
111 "DP_SV_PLAYERPHYSICS "
117 "DP_TE_EXPLOSIONRGB "
119 "DP_TE_PARTICLECUBE "
120 "DP_TE_PARTICLERAIN "
121 "DP_TE_PARTICLESNOW "
123 "DP_TE_QUADEFFECTS1 "
126 "DP_TE_STANDARDEFFECTBUILTINS "
134 qboolean checkextension(char *name)
139 for (e = ENGINE_EXTENSIONS;*e;e++)
146 while (*e && *e != ' ')
148 if (e - start == len)
149 if (!strncasecmp(start, name, len))
159 returns true if the extension is supported by the server
161 checkextension(extensionname)
164 void PF_checkextension (void)
166 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
173 This is a TERMINAL error, which will kill off the entire server.
185 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
186 ed = PROG_TO_EDICT(pr_global_struct->self);
189 Host_Error ("Program error");
196 Dumps out self, then an error message. The program is aborted and self is
197 removed, but the level can continue.
202 void PF_objerror (void)
208 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
209 ed = PROG_TO_EDICT(pr_global_struct->self);
219 Writes new values for v_forward, v_up, and v_right based on angles
223 void PF_makevectors (void)
225 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
232 Writes new values for v_forward, v_up, and v_right based on the given forward vector
233 vectorvectors(vector, vector)
236 void PF_vectorvectors (void)
238 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
239 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
246 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.
248 setorigin (entity, origin)
251 void PF_setorigin (void)
256 e = G_EDICT(OFS_PARM0);
257 org = G_VECTOR(OFS_PARM1);
258 VectorCopy (org, e->v->origin);
259 SV_LinkEdict (e, false);
263 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
267 for (i=0 ; i<3 ; i++)
269 Host_Error ("backwards mins/maxs");
271 // set derived values
272 VectorCopy (min, e->v->mins);
273 VectorCopy (max, e->v->maxs);
274 VectorSubtract (max, min, e->v->size);
276 SV_LinkEdict (e, false);
283 the size box is rotated by the current angle
284 LordHavoc: no it isn't...
286 setsize (entity, minvector, maxvector)
289 void PF_setsize (void)
294 e = G_EDICT(OFS_PARM0);
295 min = G_VECTOR(OFS_PARM1);
296 max = G_VECTOR(OFS_PARM2);
297 SetMinMaxSize (e, min, max, false);
305 setmodel(entity, model)
308 void PF_setmodel (void)
315 e = G_EDICT(OFS_PARM0);
316 m = G_STRING(OFS_PARM1);
318 // check to see if model was properly precached
319 for (i=0, check = sv.model_precache ; *check ; i++, check++)
320 if (!strcmp(*check, m))
324 Host_Error ("no precache: %s\n", m);
327 e->v->model = PR_SetString(*check);
328 e->v->modelindex = i;
330 mod = sv.models[ (int)e->v->modelindex];
333 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
335 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
342 broadcast print to everyone on server
347 void PF_bprint (void)
352 SV_BroadcastPrintf ("%s", s);
359 single print to a specific client
361 sprint(clientent, value)
364 void PF_sprint (void)
370 entnum = G_EDICTNUM(OFS_PARM0);
373 if (entnum < 1 || entnum > svs.maxclients)
375 Con_Printf ("tried to sprint to a non-client\n");
379 client = &svs.clients[entnum-1];
381 MSG_WriteChar (&client->message,svc_print);
382 MSG_WriteString (&client->message, s );
390 single print to a specific client
392 centerprint(clientent, value)
395 void PF_centerprint (void)
401 entnum = G_EDICTNUM(OFS_PARM0);
404 if (entnum < 1 || entnum > svs.maxclients)
406 Con_Printf ("tried to sprint to a non-client\n");
410 client = &svs.clients[entnum-1];
412 MSG_WriteChar (&client->message,svc_centerprint);
413 MSG_WriteString (&client->message, s );
421 vector normalize(vector)
424 void PF_normalize (void)
430 value1 = G_VECTOR(OFS_PARM0);
432 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
436 newvalue[0] = newvalue[1] = newvalue[2] = 0;
440 newvalue[0] = value1[0] * new;
441 newvalue[1] = value1[1] * new;
442 newvalue[2] = value1[2] * new;
445 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
460 value1 = G_VECTOR(OFS_PARM0);
462 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
465 G_FLOAT(OFS_RETURN) = new;
472 float vectoyaw(vector)
475 void PF_vectoyaw (void)
480 value1 = G_VECTOR(OFS_PARM0);
482 if (value1[1] == 0 && value1[0] == 0)
486 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
491 G_FLOAT(OFS_RETURN) = yaw;
499 vector vectoangles(vector)
502 void PF_vectoangles (void)
508 value1 = G_VECTOR(OFS_PARM0);
510 if (value1[1] == 0 && value1[0] == 0)
520 // LordHavoc: optimized a bit
523 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
527 else if (value1[1] > 0)
532 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
533 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
538 G_FLOAT(OFS_RETURN+0) = pitch;
539 G_FLOAT(OFS_RETURN+1) = yaw;
540 G_FLOAT(OFS_RETURN+2) = 0;
547 Returns a number from 0<= num < 1
552 void PF_random (void)
556 num = (rand ()&0x7fff) / ((float)0x7fff);
558 G_FLOAT(OFS_RETURN) = num;
565 particle(origin, color, count)
568 void PF_particle (void)
574 org = G_VECTOR(OFS_PARM0);
575 dir = G_VECTOR(OFS_PARM1);
576 color = G_FLOAT(OFS_PARM2);
577 count = G_FLOAT(OFS_PARM3);
578 SV_StartParticle (org, dir, color, count);
588 void PF_ambientsound (void)
593 float vol, attenuation;
594 int i, soundnum, large;
596 pos = G_VECTOR (OFS_PARM0);
597 samp = G_STRING(OFS_PARM1);
598 vol = G_FLOAT(OFS_PARM2);
599 attenuation = G_FLOAT(OFS_PARM3);
601 // check to see if samp was properly precached
602 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
603 if (!strcmp(*check,samp))
608 Con_Printf ("no precache: %s\n", samp);
616 // add an svc_spawnambient command to the level signon packet
619 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
621 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
623 for (i=0 ; i<3 ; i++)
624 MSG_WriteDPCoord(&sv.signon, pos[i]);
627 MSG_WriteShort (&sv.signon, soundnum);
629 MSG_WriteByte (&sv.signon, soundnum);
631 MSG_WriteByte (&sv.signon, vol*255);
632 MSG_WriteByte (&sv.signon, attenuation*64);
640 Each entity can have eight independant sound sources, like voice,
643 Channel 0 is an auto-allocate channel, the others override anything
644 already running on that entity/channel pair.
646 An attenuation of 0 will play full volume everywhere in the level.
647 Larger attenuations will drop off.
659 entity = G_EDICT(OFS_PARM0);
660 channel = G_FLOAT(OFS_PARM1);
661 sample = G_STRING(OFS_PARM2);
662 volume = G_FLOAT(OFS_PARM3) * 255;
663 attenuation = G_FLOAT(OFS_PARM4);
665 if (volume < 0 || volume > 255)
666 Host_Error ("SV_StartSound: volume = %i", volume);
668 if (attenuation < 0 || attenuation > 4)
669 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
671 if (channel < 0 || channel > 7)
672 Host_Error ("SV_StartSound: channel = %i", channel);
674 SV_StartSound (entity, channel, sample, volume, attenuation);
686 Host_Error ("break statement");
693 Used for use tracing and shot targeting
694 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
695 if the tryents flag is set.
697 traceline (vector1, vector2, tryents)
700 void PF_traceline (void)
707 pr_xfunction->builtinsprofile += 30;
709 v1 = G_VECTOR(OFS_PARM0);
710 v2 = G_VECTOR(OFS_PARM1);
711 nomonsters = G_FLOAT(OFS_PARM2);
712 ent = G_EDICT(OFS_PARM3);
714 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
716 pr_global_struct->trace_allsolid = trace.allsolid;
717 pr_global_struct->trace_startsolid = trace.startsolid;
718 pr_global_struct->trace_fraction = trace.fraction;
719 pr_global_struct->trace_inwater = trace.inwater;
720 pr_global_struct->trace_inopen = trace.inopen;
721 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
722 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
723 pr_global_struct->trace_plane_dist = trace.plane.dist;
725 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
727 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
728 // FIXME: add trace_endcontents
736 Used for use tracing and shot targeting
737 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
738 if the tryents flag is set.
740 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
743 // LordHavoc: added this for my own use, VERY useful, similar to traceline
744 void PF_tracebox (void)
746 float *v1, *v2, *m1, *m2;
751 pr_xfunction->builtinsprofile += 30;
753 v1 = G_VECTOR(OFS_PARM0);
754 m1 = G_VECTOR(OFS_PARM1);
755 m2 = G_VECTOR(OFS_PARM2);
756 v2 = G_VECTOR(OFS_PARM3);
757 nomonsters = G_FLOAT(OFS_PARM4);
758 ent = G_EDICT(OFS_PARM5);
760 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
762 pr_global_struct->trace_allsolid = trace.allsolid;
763 pr_global_struct->trace_startsolid = trace.startsolid;
764 pr_global_struct->trace_fraction = trace.fraction;
765 pr_global_struct->trace_inwater = trace.inwater;
766 pr_global_struct->trace_inopen = trace.inopen;
767 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
768 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
769 pr_global_struct->trace_plane_dist = trace.plane.dist;
771 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
773 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
776 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
777 void PF_TraceToss (void)
783 pr_xfunction->builtinsprofile += 600;
785 ent = G_EDICT(OFS_PARM0);
786 ignore = G_EDICT(OFS_PARM1);
788 trace = SV_Trace_Toss (ent, ignore);
790 pr_global_struct->trace_allsolid = trace.allsolid;
791 pr_global_struct->trace_startsolid = trace.startsolid;
792 pr_global_struct->trace_fraction = trace.fraction;
793 pr_global_struct->trace_inwater = trace.inwater;
794 pr_global_struct->trace_inopen = trace.inopen;
795 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
796 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
797 pr_global_struct->trace_plane_dist = trace.plane.dist;
799 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
801 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
809 Returns true if the given entity can move to the given position from it's
810 current position by walking or rolling.
812 scalar checkpos (entity, vector)
815 void PF_checkpos (void)
819 //============================================================================
821 qbyte checkpvs[MAX_MAP_LEAFS/8];
823 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 leaf = Mod_PointInLeaf (org, sv.worldmodel);
868 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
869 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
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)
897 // find a new check if on a new frame
898 if (sv.time - sv.lastchecktime >= 0.1)
900 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
901 sv.lastchecktime = sv.time;
904 // return check if it might be visible
905 ent = EDICT_NUM(sv.lastcheck);
906 if (ent->free || ent->v->health <= 0)
908 RETURN_EDICT(sv.edicts);
912 // if current entity can't possibly see the check entity, return 0
913 self = PROG_TO_EDICT(pr_global_struct->self);
914 VectorAdd (self->v->origin, self->v->view_ofs, view);
915 leaf = Mod_PointInLeaf (view, sv.worldmodel);
918 l = (leaf - sv.worldmodel->leafs) - 1;
919 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
922 RETURN_EDICT(sv.edicts);
927 // might be able to see it
932 //============================================================================
939 Sends text over to the client's execution buffer
941 stuffcmd (clientent, value)
944 void PF_stuffcmd (void)
950 entnum = G_EDICTNUM(OFS_PARM0);
951 if (entnum < 1 || entnum > svs.maxclients)
952 Host_Error ("Parm 0 not a client");
953 str = G_STRING(OFS_PARM1);
956 host_client = &svs.clients[entnum-1];
957 Host_ClientCommands ("%s", str);
965 Sends text over to the client's execution buffer
970 void PF_localcmd (void)
974 str = G_STRING(OFS_PARM0);
989 str = G_STRING(OFS_PARM0);
991 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
1001 void PF_cvar_set (void)
1005 var = G_STRING(OFS_PARM0);
1006 val = G_STRING(OFS_PARM1);
1008 Cvar_Set (var, val);
1015 Returns a chain of entities that have origins within a spherical area
1017 findradius (origin, radius)
1020 void PF_findradius (void)
1022 edict_t *ent, *chain;
1029 chain = (edict_t *)sv.edicts;
1031 org = G_VECTOR(OFS_PARM0);
1032 radius = G_FLOAT(OFS_PARM1);
1033 radius2 = radius * radius;
1035 ent = NEXT_EDICT(sv.edicts);
1036 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1038 pr_xfunction->builtinsprofile++;
1041 if (ent->v->solid == SOLID_NOT)
1044 // LordHavoc: compare against bounding box rather than center,
1045 // and use DotProduct instead of Length, major speedup
1046 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1047 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1048 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1049 if (DotProduct(eorg, eorg) > radius2)
1052 ent->v->chain = EDICT_TO_PROG(chain);
1056 RETURN_EDICT(chain);
1065 void PF_dprint (void)
1067 Con_DPrintf ("%s",PF_VarString(0));
1070 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1071 #define STRINGTEMP_BUFFERS 16
1072 #define STRINGTEMP_LENGTH 128
1073 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1074 static int pr_string_tempindex = 0;
1076 static char *PR_GetTempString(void)
1079 s = pr_string_temp[pr_string_tempindex];
1080 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1088 v = G_FLOAT(OFS_PARM0);
1090 s = PR_GetTempString();
1091 // LordHavoc: ftos improvement
1092 sprintf (s, "%g", v);
1093 G_INT(OFS_RETURN) = PR_SetString(s);
1099 v = G_FLOAT(OFS_PARM0);
1100 G_FLOAT(OFS_RETURN) = fabs(v);
1106 s = PR_GetTempString();
1107 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1108 G_INT(OFS_RETURN) = PR_SetString(s);
1114 s = PR_GetTempString();
1115 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1116 G_INT(OFS_RETURN) = PR_SetString(s);
1119 void PF_Spawn (void)
1122 pr_xfunction->builtinsprofile += 20;
1127 void PF_Remove (void)
1130 pr_xfunction->builtinsprofile += 20;
1132 ed = G_EDICT(OFS_PARM0);
1133 if (ed == sv.edicts)
1134 Host_Error("remove: tried to remove world\n");
1135 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1136 Host_Error("remove: tried to remove a client\n");
1141 // entity (entity start, .string field, string match) find = #5;
1149 e = G_EDICTNUM(OFS_PARM0);
1150 f = G_INT(OFS_PARM1);
1151 s = G_STRING(OFS_PARM2);
1154 RETURN_EDICT(sv.edicts);
1158 for (e++ ; e < sv.num_edicts ; e++)
1160 pr_xfunction->builtinsprofile++;
1174 RETURN_EDICT(sv.edicts);
1177 // LordHavoc: added this for searching float, int, and entity reference fields
1178 void PF_FindFloat (void)
1185 e = G_EDICTNUM(OFS_PARM0);
1186 f = G_INT(OFS_PARM1);
1187 s = G_FLOAT(OFS_PARM2);
1189 for (e++ ; e < sv.num_edicts ; e++)
1191 pr_xfunction->builtinsprofile++;
1195 if (E_FLOAT(ed,f) == s)
1202 RETURN_EDICT(sv.edicts);
1205 // chained search for strings in entity fields
1206 // entity(.string field, string match) findchain = #402;
1207 void PF_findchain (void)
1212 edict_t *ent, *chain;
1214 chain = (edict_t *)sv.edicts;
1216 f = G_INT(OFS_PARM0);
1217 s = G_STRING(OFS_PARM1);
1220 RETURN_EDICT(sv.edicts);
1224 ent = NEXT_EDICT(sv.edicts);
1225 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1227 pr_xfunction->builtinsprofile++;
1230 t = E_STRING(ent,f);
1236 ent->v->chain = EDICT_TO_PROG(chain);
1240 RETURN_EDICT(chain);
1243 // LordHavoc: chained search for float, int, and entity reference fields
1244 // entity(.string field, float match) findchainfloat = #403;
1245 void PF_findchainfloat (void)
1250 edict_t *ent, *chain;
1252 chain = (edict_t *)sv.edicts;
1254 f = G_INT(OFS_PARM0);
1255 s = G_FLOAT(OFS_PARM1);
1257 ent = NEXT_EDICT(sv.edicts);
1258 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1260 pr_xfunction->builtinsprofile++;
1263 if (E_FLOAT(ent,f) != s)
1266 ent->v->chain = EDICT_TO_PROG(chain);
1270 RETURN_EDICT(chain);
1273 void PR_CheckEmptyString (char *s)
1276 Host_Error ("Bad string");
1279 void PF_precache_file (void)
1280 { // precache_file is only used to copy files with qcc, it does nothing
1281 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1284 void PF_precache_sound (void)
1289 if (sv.state != ss_loading)
1290 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1292 s = G_STRING(OFS_PARM0);
1293 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1294 PR_CheckEmptyString (s);
1296 for (i=0 ; i<MAX_SOUNDS ; i++)
1298 if (!sv.sound_precache[i])
1300 sv.sound_precache[i] = s;
1303 if (!strcmp(sv.sound_precache[i], s))
1306 Host_Error ("PF_precache_sound: overflow");
1309 void PF_precache_model (void)
1314 if (sv.state != ss_loading)
1315 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1317 s = G_STRING(OFS_PARM0);
1318 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1320 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1321 PR_CheckEmptyString (s);
1323 for (i=0 ; i<MAX_MODELS ; i++)
1325 if (!sv.model_precache[i])
1327 sv.model_precache[i] = s;
1328 sv.models[i] = Mod_ForName (s, true, false, false);
1331 if (!strcmp(sv.model_precache[i], s))
1334 Host_Error ("PF_precache_model: overflow");
1338 void PF_coredump (void)
1343 void PF_traceon (void)
1348 void PF_traceoff (void)
1353 void PF_eprint (void)
1355 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1362 float(float yaw, float dist) walkmove
1365 void PF_walkmove (void)
1373 ent = PROG_TO_EDICT(pr_global_struct->self);
1374 yaw = G_FLOAT(OFS_PARM0);
1375 dist = G_FLOAT(OFS_PARM1);
1377 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1379 G_FLOAT(OFS_RETURN) = 0;
1383 yaw = yaw*M_PI*2 / 360;
1385 move[0] = cos(yaw)*dist;
1386 move[1] = sin(yaw)*dist;
1389 // save program state, because SV_movestep may call other progs
1390 oldf = pr_xfunction;
1391 oldself = pr_global_struct->self;
1393 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1396 // restore program state
1397 pr_xfunction = oldf;
1398 pr_global_struct->self = oldself;
1408 void PF_droptofloor (void)
1414 ent = PROG_TO_EDICT(pr_global_struct->self);
1416 VectorCopy (ent->v->origin, end);
1419 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1421 if (trace.fraction == 1)
1422 G_FLOAT(OFS_RETURN) = 0;
1425 VectorCopy (trace.endpos, ent->v->origin);
1426 SV_LinkEdict (ent, false);
1427 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1428 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1429 G_FLOAT(OFS_RETURN) = 1;
1430 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1431 ent->suspendedinairflag = true;
1439 void(float style, string value) lightstyle
1442 void PF_lightstyle (void)
1449 style = G_FLOAT(OFS_PARM0);
1450 val = G_STRING(OFS_PARM1);
1452 // change the string in sv
1453 sv.lightstyles[style] = val;
1455 // send message to all clients on this server
1456 if (sv.state != ss_active)
1459 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1460 if (client->active || client->spawned)
1462 MSG_WriteChar (&client->message, svc_lightstyle);
1463 MSG_WriteChar (&client->message,style);
1464 MSG_WriteString (&client->message, val);
1471 f = G_FLOAT(OFS_PARM0);
1473 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1475 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1477 void PF_floor (void)
1479 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1483 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1492 void PF_checkbottom (void)
1494 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1502 void PF_pointcontents (void)
1504 G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1511 entity nextent(entity)
1514 void PF_nextent (void)
1519 i = G_EDICTNUM(OFS_PARM0);
1522 pr_xfunction->builtinsprofile++;
1524 if (i == sv.num_edicts)
1526 RETURN_EDICT(sv.edicts);
1542 Pick a vector for the player to shoot along
1543 vector aim(entity, missilespeed)
1548 edict_t *ent, *check, *bestent;
1549 vec3_t start, dir, end, bestdir;
1552 float dist, bestdist;
1555 ent = G_EDICT(OFS_PARM0);
1556 speed = G_FLOAT(OFS_PARM1);
1558 VectorCopy (ent->v->origin, start);
1561 // try sending a trace straight
1562 VectorCopy (pr_global_struct->v_forward, dir);
1563 VectorMA (start, 2048, dir, end);
1564 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1565 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1566 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1568 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1573 // try all possible entities
1574 VectorCopy (dir, bestdir);
1575 bestdist = sv_aim.value;
1578 check = NEXT_EDICT(sv.edicts);
1579 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1581 pr_xfunction->builtinsprofile++;
1582 if (check->v->takedamage != DAMAGE_AIM)
1586 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1587 continue; // don't aim at teammate
1588 for (j=0 ; j<3 ; j++)
1589 end[j] = check->v->origin[j]
1590 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1591 VectorSubtract (end, start, dir);
1592 VectorNormalize (dir);
1593 dist = DotProduct (dir, pr_global_struct->v_forward);
1594 if (dist < bestdist)
1595 continue; // to far to turn
1596 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1597 if (tr.ent == check)
1598 { // can shoot at this one
1606 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1607 dist = DotProduct (dir, pr_global_struct->v_forward);
1608 VectorScale (pr_global_struct->v_forward, dist, end);
1610 VectorNormalize (end);
1611 VectorCopy (end, G_VECTOR(OFS_RETURN));
1615 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1623 This was a major timewaster in progs, so it was converted to C
1626 void PF_changeyaw (void)
1629 float ideal, current, move, speed;
1631 ent = PROG_TO_EDICT(pr_global_struct->self);
1632 current = ANGLEMOD(ent->v->angles[1]);
1633 ideal = ent->v->ideal_yaw;
1634 speed = ent->v->yaw_speed;
1636 if (current == ideal)
1638 move = ideal - current;
1639 if (ideal > current)
1660 ent->v->angles[1] = ANGLEMOD (current + move);
1668 void PF_changepitch (void)
1671 float ideal, current, move, speed;
1674 ent = G_EDICT(OFS_PARM0);
1675 current = ANGLEMOD( ent->v->angles[0] );
1676 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1677 ideal = val->_float;
1680 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1683 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1684 speed = val->_float;
1687 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1691 if (current == ideal)
1693 move = ideal - current;
1694 if (ideal > current)
1715 ent->v->angles[0] = ANGLEMOD (current + move);
1719 ===============================================================================
1723 ===============================================================================
1726 #define MSG_BROADCAST 0 // unreliable to all
1727 #define MSG_ONE 1 // reliable to one (msg_entity)
1728 #define MSG_ALL 2 // reliable to all
1729 #define MSG_INIT 3 // write to the init string
1731 sizebuf_t *WriteDest (void)
1737 dest = G_FLOAT(OFS_PARM0);
1741 return &sv.datagram;
1744 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1745 entnum = NUM_FOR_EDICT(ent);
1746 if (entnum < 1 || entnum > svs.maxclients)
1747 Host_Error ("WriteDest: not a client");
1748 return &svs.clients[entnum-1].message;
1751 return &sv.reliable_datagram;
1757 Host_Error ("WriteDest: bad destination");
1764 void PF_WriteByte (void)
1766 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1769 void PF_WriteChar (void)
1771 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1774 void PF_WriteShort (void)
1776 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1779 void PF_WriteLong (void)
1781 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1784 void PF_WriteAngle (void)
1786 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1789 void PF_WriteCoord (void)
1791 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1794 void PF_WriteString (void)
1796 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1800 void PF_WriteEntity (void)
1802 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1805 //=============================================================================
1807 void PF_makestatic (void)
1812 ent = G_EDICT(OFS_PARM0);
1815 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1820 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1821 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1822 MSG_WriteShort (&sv.signon, ent->v->frame);
1826 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1827 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1828 MSG_WriteByte (&sv.signon, ent->v->frame);
1831 MSG_WriteByte (&sv.signon, ent->v->colormap);
1832 MSG_WriteByte (&sv.signon, ent->v->skin);
1833 for (i=0 ; i<3 ; i++)
1835 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1836 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1839 // throw the entity away now
1843 //=============================================================================
1850 void PF_setspawnparms (void)
1856 ent = G_EDICT(OFS_PARM0);
1857 i = NUM_FOR_EDICT(ent);
1858 if (i < 1 || i > svs.maxclients)
1859 Host_Error ("Entity is not a client");
1861 // copy spawn parms out of the client_t
1862 client = svs.clients + (i-1);
1864 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1865 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1873 void PF_changelevel (void)
1877 // make sure we don't issue two changelevels
1878 if (svs.changelevel_issued)
1880 svs.changelevel_issued = true;
1882 s = G_STRING(OFS_PARM0);
1883 Cbuf_AddText (va("changelevel %s\n",s));
1888 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1893 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1898 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1905 Returns a vector of length < 1
1910 void PF_randomvec (void)
1915 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1916 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1917 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1919 while (DotProduct(temp, temp) >= 1);
1920 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1923 void SV_LightPoint (vec3_t color, vec3_t p);
1928 Returns a color vector indicating the lighting at the requested point.
1930 (Internal Operation note: actually measures the light beneath the point, just like
1931 the model lighting on the client)
1936 void PF_GetLight (void)
1940 p = G_VECTOR(OFS_PARM0);
1941 SV_LightPoint (color, p);
1942 VectorCopy (color, G_VECTOR(OFS_RETURN));
1945 #define MAX_QC_CVARS 128
1946 cvar_t qc_cvar[MAX_QC_CVARS];
1949 void PF_registercvar (void)
1953 name = G_STRING(OFS_PARM0);
1954 value = G_STRING(OFS_PARM1);
1955 G_FLOAT(OFS_RETURN) = 0;
1956 // first check to see if it has already been defined
1957 if (Cvar_FindVar (name))
1960 // check for overlap with a command
1961 if (Cmd_Exists (name))
1963 Con_Printf ("PF_registercvar: %s is a command\n", name);
1967 if (currentqc_cvar >= MAX_QC_CVARS)
1968 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1970 // copy the name and value
1971 variable = &qc_cvar[currentqc_cvar++];
1972 variable->name = Z_Malloc (strlen(name)+1);
1973 strcpy (variable->name, name);
1974 variable->string = Z_Malloc (strlen(value)+1);
1975 strcpy (variable->string, value);
1976 variable->value = atof (value);
1978 Cvar_RegisterVariable(variable);
1979 G_FLOAT(OFS_RETURN) = 1; // success
1986 returns the minimum of two supplied floats
1993 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1995 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1996 else if (pr_argc >= 3)
1999 float f = G_FLOAT(OFS_PARM0);
2000 for (i = 1;i < pr_argc;i++)
2001 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2002 f = G_FLOAT((OFS_PARM0+i*3));
2003 G_FLOAT(OFS_RETURN) = f;
2006 Host_Error("min: must supply at least 2 floats\n");
2013 returns the maximum of two supplied floats
2020 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2022 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2023 else if (pr_argc >= 3)
2026 float f = G_FLOAT(OFS_PARM0);
2027 for (i = 1;i < pr_argc;i++)
2028 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2029 f = G_FLOAT((OFS_PARM0+i*3));
2030 G_FLOAT(OFS_RETURN) = f;
2033 Host_Error("max: must supply at least 2 floats\n");
2040 returns number bounded by supplied range
2042 min(min, value, max)
2045 void PF_bound (void)
2047 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2054 returns a raised to power b
2061 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2068 copies data from one entity to another
2070 copyentity(src, dst)
2073 void PF_copyentity (void)
2076 in = G_EDICT(OFS_PARM0);
2077 out = G_EDICT(OFS_PARM1);
2078 memcpy(out->v, in->v, progs->entityfields * 4);
2085 sets the color of a client and broadcasts the update to all connected clients
2087 setcolor(clientent, value)
2090 void PF_setcolor (void)
2095 entnum = G_EDICTNUM(OFS_PARM0);
2096 i = G_FLOAT(OFS_PARM1);
2098 if (entnum < 1 || entnum > svs.maxclients)
2100 Con_Printf ("tried to setcolor a non-client\n");
2104 client = &svs.clients[entnum-1];
2106 EDICT_NUM(client->edictnumber)->v->team = (i & 15) + 1;
2108 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2109 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2110 MSG_WriteByte (&sv.reliable_datagram, i);
2117 effect(origin, modelname, startframe, framecount, framerate)
2120 void PF_effect (void)
2123 s = G_STRING(OFS_PARM1);
2125 Host_Error("effect: no model specified\n");
2127 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2130 void PF_te_blood (void)
2132 if (G_FLOAT(OFS_PARM2) < 1)
2134 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2135 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2137 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2138 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2139 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2141 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2142 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2143 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2145 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2148 void PF_te_bloodshower (void)
2150 if (G_FLOAT(OFS_PARM3) < 1)
2152 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2153 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2155 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2156 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2157 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2159 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2160 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2161 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2163 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2165 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2168 void PF_te_explosionrgb (void)
2170 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2171 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2173 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2174 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2175 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2177 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2178 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2179 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2182 void PF_te_particlecube (void)
2184 if (G_FLOAT(OFS_PARM3) < 1)
2186 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2187 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2189 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2190 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2191 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2193 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2194 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2195 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2197 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2198 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2199 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2201 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2203 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2204 // gravity true/false
2205 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2207 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2210 void PF_te_particlerain (void)
2212 if (G_FLOAT(OFS_PARM3) < 1)
2214 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2215 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2217 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2218 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2219 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2221 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2222 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2223 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2225 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2226 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2227 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2229 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2231 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2234 void PF_te_particlesnow (void)
2236 if (G_FLOAT(OFS_PARM3) < 1)
2238 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2239 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2241 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2242 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2243 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2245 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2246 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2247 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2249 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2250 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2251 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2253 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2255 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2258 void PF_te_spark (void)
2260 if (G_FLOAT(OFS_PARM2) < 1)
2262 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2263 MSG_WriteByte(&sv.datagram, TE_SPARK);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2266 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2267 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2269 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2270 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2271 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2273 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2276 void PF_te_gunshotquad (void)
2278 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2279 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2286 void PF_te_spikequad (void)
2288 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2289 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2292 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2293 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2296 void PF_te_superspikequad (void)
2298 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2299 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2301 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2302 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2303 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2306 void PF_te_explosionquad (void)
2308 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2309 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2312 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2313 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2316 void PF_te_smallflash (void)
2318 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2319 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
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]);
2326 void PF_te_customflash (void)
2328 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2330 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2331 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2333 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2334 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2335 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2337 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2339 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2341 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2342 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2343 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2346 void PF_te_gunshot (void)
2348 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2349 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2353 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2356 void PF_te_spike (void)
2358 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2359 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2363 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2366 void PF_te_superspike (void)
2368 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2369 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2376 void PF_te_explosion (void)
2378 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2379 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2381 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2382 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2383 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2386 void PF_te_tarexplosion (void)
2388 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2389 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2392 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2393 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2396 void PF_te_wizspike (void)
2398 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2399 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2402 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2403 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2406 void PF_te_knightspike (void)
2408 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2409 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2413 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2416 void PF_te_lavasplash (void)
2418 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2419 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2423 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2426 void PF_te_teleport (void)
2428 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2429 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2433 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2436 void PF_te_explosion2 (void)
2438 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2439 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2441 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2442 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2443 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2445 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2448 void PF_te_lightning1 (void)
2450 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2451 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2453 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2455 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2456 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2457 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2464 void PF_te_lightning2 (void)
2466 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2467 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2469 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2472 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2473 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2477 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2480 void PF_te_lightning3 (void)
2482 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2483 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2485 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2487 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2488 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2489 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2496 void PF_te_beam (void)
2498 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2499 MSG_WriteByte(&sv.datagram, TE_BEAM);
2501 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2503 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2504 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2505 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2508 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2509 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2512 void PF_te_plasmaburn (void)
2514 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2515 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2516 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2517 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2518 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2521 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2524 vec3_t v1, clipplanenormal, normal;
2525 vec_t clipplanedist, clipdist;
2527 if (surf->flags & SURF_PLANEBACK)
2528 VectorNegate(surf->plane->normal, normal);
2530 VectorCopy(surf->plane->normal, normal);
2531 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2533 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2534 VectorNormalizeFast(v1);
2535 CrossProduct(v1, normal, clipplanenormal);
2536 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2537 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2540 clipdist = -clipdist;
2541 VectorMA(out, clipdist, clipplanenormal, out);
2546 static msurface_t *getsurface(edict_t *ed, int surfnum)
2550 if (!ed || ed->free)
2552 modelindex = ed->v->modelindex;
2553 if (modelindex < 1 || modelindex >= MAX_MODELS)
2555 model = sv.models[modelindex];
2556 if (model->type != mod_brush)
2558 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2560 return model->surfaces + surfnum + model->firstmodelsurface;
2564 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2565 void PF_getsurfacenumpoints(void)
2568 // return 0 if no such surface
2569 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2571 G_FLOAT(OFS_RETURN) = 0;
2575 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2577 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2578 void PF_getsurfacepoint(void)
2583 VectorClear(G_VECTOR(OFS_RETURN));
2584 ed = G_EDICT(OFS_PARM0);
2585 if (!ed || ed->free)
2587 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2589 pointnum = G_FLOAT(OFS_PARM2);
2590 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2592 // FIXME: implement rotation/scaling
2593 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2595 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2596 void PF_getsurfacenormal(void)
2599 VectorClear(G_VECTOR(OFS_RETURN));
2600 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2602 // FIXME: implement rotation/scaling
2603 if (surf->flags & SURF_PLANEBACK)
2604 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2606 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2608 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2609 void PF_getsurfacetexture(void)
2612 G_INT(OFS_RETURN) = 0;
2613 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2615 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2617 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2618 void PF_getsurfacenearpoint(void)
2620 int surfnum, best, modelindex;
2622 vec_t dist, bestdist;
2627 G_FLOAT(OFS_RETURN) = -1;
2628 ed = G_EDICT(OFS_PARM0);
2629 point = G_VECTOR(OFS_PARM1);
2631 if (!ed || ed->free)
2633 modelindex = ed->v->modelindex;
2634 if (modelindex < 1 || modelindex >= MAX_MODELS)
2636 model = sv.models[modelindex];
2637 if (model->type != mod_brush)
2640 // FIXME: implement rotation/scaling
2641 VectorSubtract(point, ed->v->origin, p);
2643 bestdist = 1000000000;
2644 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2646 surf = model->surfaces + surfnum + model->firstmodelsurface;
2647 dist = PlaneDiff(p, surf->plane);
2649 if (dist < bestdist)
2651 clippointtosurface(surf, p, clipped);
2652 VectorSubtract(clipped, p, clipped);
2653 dist += DotProduct(clipped, clipped);
2654 if (dist < bestdist)
2661 G_FLOAT(OFS_RETURN) = best;
2663 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2664 void PF_getsurfaceclippedpoint(void)
2669 VectorClear(G_VECTOR(OFS_RETURN));
2670 ed = G_EDICT(OFS_PARM0);
2671 if (!ed || ed->free)
2673 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2675 // FIXME: implement rotation/scaling
2676 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2677 clippointtosurface(surf, p, out);
2678 // FIXME: implement rotation/scaling
2679 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2682 #define MAX_PRFILES 256
2684 qfile_t *pr_files[MAX_PRFILES];
2686 void PR_Files_Init(void)
2688 memset(pr_files, 0, sizeof(pr_files));
2691 void PR_Files_CloseAll(void)
2694 for (i = 0;i < MAX_PRFILES;i++)
2697 FS_Close(pr_files[i]);
2702 //float(string s) stof = #81; // get numerical value from a string
2705 char *s = PF_VarString(0);
2706 G_FLOAT(OFS_RETURN) = atof(s);
2709 //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
2713 char *modestring, *filename;
2714 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2715 if (pr_files[filenum] == NULL)
2717 if (filenum >= MAX_PRFILES)
2719 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2720 G_FLOAT(OFS_RETURN) = -2;
2723 mode = G_FLOAT(OFS_PARM1);
2726 case 0: // FILE_READ
2729 case 1: // FILE_APPEND
2732 case 2: // FILE_WRITE
2736 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2737 G_FLOAT(OFS_RETURN) = -3;
2740 filename = G_STRING(OFS_PARM0);
2741 // .. is parent directory on many platforms
2742 // / is parent directory on Amiga
2743 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2744 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2745 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2747 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2748 G_FLOAT(OFS_RETURN) = -4;
2751 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2752 if (pr_files[filenum] == NULL)
2753 G_FLOAT(OFS_RETURN) = -1;
2755 G_FLOAT(OFS_RETURN) = filenum;
2758 //void(float fhandle) fclose = #111; // closes a file
2759 void PF_fclose(void)
2761 int filenum = G_FLOAT(OFS_PARM0);
2762 if (filenum < 0 || filenum >= MAX_PRFILES)
2764 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2767 if (pr_files[filenum] == NULL)
2769 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2772 FS_Close(pr_files[filenum]);
2773 pr_files[filenum] = NULL;
2776 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2780 static char string[MAX_VARSTRING];
2781 int filenum = G_FLOAT(OFS_PARM0);
2782 if (filenum < 0 || filenum >= MAX_PRFILES)
2784 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2787 if (pr_files[filenum] == NULL)
2789 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2795 c = FS_Getc(pr_files[filenum]);
2796 if (c == '\r' || c == '\n' || c < 0)
2798 if (end < MAX_VARSTRING - 1)
2802 // remove \n following \r
2804 c = FS_Getc(pr_files[filenum]);
2805 if (developer.integer)
2806 Con_Printf("fgets: %s\n", string);
2808 G_INT(OFS_RETURN) = PR_SetString(string);
2810 G_INT(OFS_RETURN) = 0;
2813 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2817 char *s = PF_VarString(1);
2818 int filenum = G_FLOAT(OFS_PARM0);
2819 if (filenum < 0 || filenum >= MAX_PRFILES)
2821 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2824 if (pr_files[filenum] == NULL)
2826 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2829 if ((stringlength = strlen(s)))
2830 FS_Write(pr_files[filenum], s, stringlength);
2831 if (developer.integer)
2832 Con_Printf("fputs: %s\n", s);
2835 //float(string s) strlen = #114; // returns how many characters are in a string
2836 void PF_strlen(void)
2839 s = G_STRING(OFS_PARM0);
2841 G_FLOAT(OFS_RETURN) = strlen(s);
2843 G_FLOAT(OFS_RETURN) = 0;
2846 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2847 void PF_strcat(void)
2849 char *s = PF_VarString(0);
2850 G_INT(OFS_RETURN) = PR_SetString(s);
2853 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2854 void PF_substring(void)
2856 int end, start, length, slen;
2858 char string[MAX_VARSTRING];
2859 s = G_STRING(OFS_PARM0);
2860 start = G_FLOAT(OFS_PARM1);
2861 length = G_FLOAT(OFS_PARM2);
2868 if (length > slen - start)
2869 length = slen - start;
2870 if (length > MAX_VARSTRING - 1)
2871 length = MAX_VARSTRING - 1;
2875 memcpy(string, s + start, length);
2879 G_INT(OFS_RETURN) = PR_SetString(string);
2882 //vector(string s) stov = #117; // returns vector value from a string
2885 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2888 //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)
2889 void PF_strzone(void)
2892 in = G_STRING(OFS_PARM0);
2893 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2895 G_INT(OFS_RETURN) = PR_SetString(out);
2898 //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!!!)
2899 void PF_strunzone(void)
2901 Mem_Free(G_STRING(OFS_PARM0));
2904 builtin_t pr_builtin[] =
2907 PF_makevectors, // #1 void(entity e) makevectors
2908 PF_setorigin, // #2 void(entity e, vector o) setorigin
2909 PF_setmodel, // #3 void(entity e, string m) setmodel
2910 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2911 NULL, // #5 void(entity e, vector min, vector max) setabssize
2912 PF_break, // #6 void() break
2913 PF_random, // #7 float() random
2914 PF_sound, // #8 void(entity e, float chan, string samp) sound
2915 PF_normalize, // #9 vector(vector v) normalize
2916 PF_error, // #10 void(string e) error
2917 PF_objerror, // #11 void(string e) objerror
2918 PF_vlen, // #12 float(vector v) vlen
2919 PF_vectoyaw, // #13 float(vector v) vectoyaw
2920 PF_Spawn, // #14 entity() spawn
2921 PF_Remove, // #15 void(entity e) remove
2922 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2923 PF_checkclient, // #17 entity() clientlist
2924 PF_Find, // #18 entity(entity start, .string fld, string match) find
2925 PF_precache_sound, // #19 void(string s) precache_sound
2926 PF_precache_model, // #20 void(string s) precache_model
2927 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2928 PF_findradius, // #22 entity(vector org, float rad) findradius
2929 PF_bprint, // #23 void(string s) bprint
2930 PF_sprint, // #24 void(entity client, string s) sprint
2931 PF_dprint, // #25 void(string s) dprint
2932 PF_ftos, // #26 void(string s) ftos
2933 PF_vtos, // #27 void(string s) vtos
2934 PF_coredump, // #28 void() coredump
2935 PF_traceon, // #29 void() traceon
2936 PF_traceoff, // #30 void() traceoff
2937 PF_eprint, // #31 void(entity e) eprint
2938 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2940 PF_droptofloor, // #34 float() droptofloor
2941 PF_lightstyle, // #35 void(float style, string value) lightstyle
2942 PF_rint, // #36 float(float v) rint
2943 PF_floor, // #37 float(float v) floor
2944 PF_ceil, // #38 float(float v) ceil
2946 PF_checkbottom, // #40 float(entity e) checkbottom
2947 PF_pointcontents , // #41 float(vector v) pointcontents
2949 PF_fabs, // #43 float(float f) fabs
2950 PF_aim, // #44 vector(entity e, float speed) aim
2951 PF_cvar, // #45 float(string s) cvar
2952 PF_localcmd, // #46 void(string s) localcmd
2953 PF_nextent, // #47 entity(entity e) nextent
2954 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
2955 PF_changeyaw, // #49 void() ChangeYaw
2957 PF_vectoangles, // #51 vector(vector v) vectoangles
2958 PF_WriteByte, // #52 void(float to, float f) WriteByte
2959 PF_WriteChar, // #53 void(float to, float f) WriteChar
2960 PF_WriteShort, // #54 void(float to, float f) WriteShort
2961 PF_WriteLong, // #55 void(float to, float f) WriteLong
2962 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
2963 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
2964 PF_WriteString, // #58 void(float to, string s) WriteString
2965 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
2966 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2967 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2968 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2969 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2970 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2971 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2973 SV_MoveToGoal, // #67 void(float step) movetogoal
2974 PF_precache_file, // #68 string(string s) precache_file
2975 PF_makestatic, // #69 void(entity e) makestatic
2976 PF_changelevel, // #70 void(string s) changelevel
2978 PF_cvar_set, // #72 void(string var, string val) cvar_set
2979 PF_centerprint, // #73 void(entity client, strings) centerprint
2980 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2981 PF_precache_model, // #75 string(string s) precache_model2
2982 PF_precache_sound, // #76 string(string s) precache_sound2
2983 PF_precache_file, // #77 string(string s) precache_file2
2984 PF_setspawnparms, // #78 void(entity e) setspawnparms
2987 PF_stof, // #81 float(string s) stof (FRIK_FILE)
2996 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2997 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2998 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2999 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3000 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3001 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3002 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3003 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3004 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3005 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3016 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3017 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3018 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3019 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3020 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3021 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3022 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3023 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3024 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3025 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3026 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3027 a a a a a a a a // #120-199
3028 a a a a a a a a a a // #200-299
3029 a a a a a a a a a a // #300-399
3030 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3031 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3032 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3033 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3034 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3035 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3036 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3037 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3038 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3039 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3040 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3041 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3042 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3043 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3044 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3045 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3046 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3047 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3048 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3049 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3050 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3051 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3052 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3053 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3054 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3055 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3056 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3057 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3058 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3059 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3060 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3061 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3062 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3063 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3064 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3065 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3066 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3067 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3068 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3069 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3070 a a a a a a // #440-499 (LordHavoc)
3073 builtin_t *pr_builtins = pr_builtin;
3074 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3076 void PR_Cmd_Init(void)
3078 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3082 void PR_Cmd_Reset(void)
3084 Mem_EmptyPool(pr_strings_mempool);
3085 PR_Files_CloseAll();