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 =
77 "DP_ENT_CUSTOMCOLORMAP "
78 "DP_ENT_EXTERIORMODELTOCLIENT "
79 "DP_ENT_LOWPRECISION "
88 "DP_MOVETYPEBOUNCEMISSILE "
94 "DP_QC_FINDCHAINFLOAT "
100 "DP_QC_SINCOSSQRTPOW "
103 "DP_QC_VECTORVECTORS "
109 "DP_SV_DRAWONLYTOCLIENT "
111 "DP_SV_EXTERIORMODELTOCLIENT "
112 "DP_SV_NODRAWTOCLIENT "
113 "DP_SV_PLAYERPHYSICS "
119 "DP_TE_EXPLOSIONRGB "
121 "DP_TE_PARTICLECUBE "
122 "DP_TE_PARTICLERAIN "
123 "DP_TE_PARTICLESNOW "
125 "DP_TE_QUADEFFECTS1 "
128 "DP_TE_STANDARDEFFECTBUILTINS "
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 ? MOVE_NOMONSTERS : MOVE_NORMAL, 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)
833 // cycle to the next one
837 if (check > svs.maxclients)
838 check = svs.maxclients;
840 if (check == svs.maxclients)
847 pr_xfunction->builtinsprofile++;
848 if (i == svs.maxclients+1)
854 break; // didn't find anything else
858 if (ent->v->health <= 0)
860 if ((int)ent->v->flags & FL_NOTARGET)
863 // anything that is a client, or has a client as an enemy
867 // get the PVS for the entity
868 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
869 leaf = Mod_PointInLeaf (org, sv.worldmodel);
870 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
871 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
880 Returns a client (or object that has a client enemy) that would be a
883 If there is more than one valid option, they are cycled each frame
885 If (self.origin + self.viewofs) is not in the PVS of the current target,
886 it is not returned at all.
891 int c_invis, c_notvis;
892 void PF_checkclient (void)
899 // find a new check if on a new frame
900 if (sv.time - sv.lastchecktime >= 0.1)
902 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
903 sv.lastchecktime = sv.time;
906 // return check if it might be visible
907 ent = EDICT_NUM(sv.lastcheck);
908 if (ent->e->free || ent->v->health <= 0)
910 RETURN_EDICT(sv.edicts);
914 // if current entity can't possibly see the check entity, return 0
915 self = PROG_TO_EDICT(pr_global_struct->self);
916 VectorAdd (self->v->origin, self->v->view_ofs, view);
917 leaf = Mod_PointInLeaf (view, sv.worldmodel);
920 l = (leaf - sv.worldmodel->leafs) - 1;
921 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
924 RETURN_EDICT(sv.edicts);
929 // might be able to see it
934 //============================================================================
941 Sends text over to the client's execution buffer
943 stuffcmd (clientent, value)
946 void PF_stuffcmd (void)
952 entnum = G_EDICTNUM(OFS_PARM0);
953 if (entnum < 1 || entnum > svs.maxclients)
954 Host_Error ("Parm 0 not a client");
955 str = G_STRING(OFS_PARM1);
958 host_client = &svs.clients[entnum-1];
959 Host_ClientCommands ("%s", str);
967 Sends text over to the client's execution buffer
972 void PF_localcmd (void)
976 str = G_STRING(OFS_PARM0);
991 str = G_STRING(OFS_PARM0);
993 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
1003 void PF_cvar_set (void)
1007 var = G_STRING(OFS_PARM0);
1008 val = G_STRING(OFS_PARM1);
1010 Cvar_Set (var, val);
1017 Returns a chain of entities that have origins within a spherical area
1019 findradius (origin, radius)
1022 void PF_findradius (void)
1024 edict_t *ent, *chain;
1031 chain = (edict_t *)sv.edicts;
1033 org = G_VECTOR(OFS_PARM0);
1034 radius = G_FLOAT(OFS_PARM1);
1035 radius2 = radius * radius;
1037 ent = NEXT_EDICT(sv.edicts);
1038 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1040 pr_xfunction->builtinsprofile++;
1043 if (ent->v->solid == SOLID_NOT)
1046 // LordHavoc: compare against bounding box rather than center,
1047 // and use DotProduct instead of Length, major speedup
1048 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1049 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1050 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1051 if (DotProduct(eorg, eorg) > radius2)
1054 ent->v->chain = EDICT_TO_PROG(chain);
1058 RETURN_EDICT(chain);
1067 void PF_dprint (void)
1069 Con_DPrintf ("%s",PF_VarString(0));
1072 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1073 #define STRINGTEMP_BUFFERS 16
1074 #define STRINGTEMP_LENGTH 128
1075 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1076 static int pr_string_tempindex = 0;
1078 static char *PR_GetTempString(void)
1081 s = pr_string_temp[pr_string_tempindex];
1082 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1090 v = G_FLOAT(OFS_PARM0);
1092 s = PR_GetTempString();
1093 // LordHavoc: ftos improvement
1094 sprintf (s, "%g", v);
1095 G_INT(OFS_RETURN) = PR_SetString(s);
1101 v = G_FLOAT(OFS_PARM0);
1102 G_FLOAT(OFS_RETURN) = fabs(v);
1108 s = PR_GetTempString();
1109 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1110 G_INT(OFS_RETURN) = PR_SetString(s);
1116 s = PR_GetTempString();
1117 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1118 G_INT(OFS_RETURN) = PR_SetString(s);
1121 void PF_Spawn (void)
1124 pr_xfunction->builtinsprofile += 20;
1129 void PF_Remove (void)
1132 pr_xfunction->builtinsprofile += 20;
1134 ed = G_EDICT(OFS_PARM0);
1135 if (ed == sv.edicts)
1136 Host_Error("remove: tried to remove world\n");
1137 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1138 Host_Error("remove: tried to remove a client\n");
1143 // entity (entity start, .string field, string match) find = #5;
1151 e = G_EDICTNUM(OFS_PARM0);
1152 f = G_INT(OFS_PARM1);
1153 s = G_STRING(OFS_PARM2);
1156 RETURN_EDICT(sv.edicts);
1160 for (e++ ; e < sv.num_edicts ; e++)
1162 pr_xfunction->builtinsprofile++;
1176 RETURN_EDICT(sv.edicts);
1179 // LordHavoc: added this for searching float, int, and entity reference fields
1180 void PF_FindFloat (void)
1187 e = G_EDICTNUM(OFS_PARM0);
1188 f = G_INT(OFS_PARM1);
1189 s = G_FLOAT(OFS_PARM2);
1191 for (e++ ; e < sv.num_edicts ; e++)
1193 pr_xfunction->builtinsprofile++;
1197 if (E_FLOAT(ed,f) == s)
1204 RETURN_EDICT(sv.edicts);
1207 // chained search for strings in entity fields
1208 // entity(.string field, string match) findchain = #402;
1209 void PF_findchain (void)
1214 edict_t *ent, *chain;
1216 chain = (edict_t *)sv.edicts;
1218 f = G_INT(OFS_PARM0);
1219 s = G_STRING(OFS_PARM1);
1222 RETURN_EDICT(sv.edicts);
1226 ent = NEXT_EDICT(sv.edicts);
1227 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1229 pr_xfunction->builtinsprofile++;
1232 t = E_STRING(ent,f);
1238 ent->v->chain = EDICT_TO_PROG(chain);
1242 RETURN_EDICT(chain);
1245 // LordHavoc: chained search for float, int, and entity reference fields
1246 // entity(.string field, float match) findchainfloat = #403;
1247 void PF_findchainfloat (void)
1252 edict_t *ent, *chain;
1254 chain = (edict_t *)sv.edicts;
1256 f = G_INT(OFS_PARM0);
1257 s = G_FLOAT(OFS_PARM1);
1259 ent = NEXT_EDICT(sv.edicts);
1260 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1262 pr_xfunction->builtinsprofile++;
1265 if (E_FLOAT(ent,f) != s)
1268 ent->v->chain = EDICT_TO_PROG(chain);
1272 RETURN_EDICT(chain);
1275 void PR_CheckEmptyString (char *s)
1278 Host_Error ("Bad string");
1281 void PF_precache_file (void)
1282 { // precache_file is only used to copy files with qcc, it does nothing
1283 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1286 void PF_precache_sound (void)
1291 if (sv.state != ss_loading)
1292 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1294 s = G_STRING(OFS_PARM0);
1295 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1296 PR_CheckEmptyString (s);
1298 for (i=0 ; i<MAX_SOUNDS ; i++)
1300 if (!sv.sound_precache[i])
1302 sv.sound_precache[i] = s;
1305 if (!strcmp(sv.sound_precache[i], s))
1308 Host_Error ("PF_precache_sound: overflow");
1311 void PF_precache_model (void)
1316 if (sv.state != ss_loading)
1317 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1319 s = G_STRING(OFS_PARM0);
1320 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1322 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1323 PR_CheckEmptyString (s);
1325 for (i=0 ; i<MAX_MODELS ; i++)
1327 if (!sv.model_precache[i])
1329 sv.model_precache[i] = s;
1330 sv.models[i] = Mod_ForName (s, true, false, false);
1333 if (!strcmp(sv.model_precache[i], s))
1336 Host_Error ("PF_precache_model: overflow");
1340 void PF_coredump (void)
1345 void PF_traceon (void)
1350 void PF_traceoff (void)
1355 void PF_eprint (void)
1357 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1364 float(float yaw, float dist) walkmove
1367 void PF_walkmove (void)
1375 ent = PROG_TO_EDICT(pr_global_struct->self);
1376 yaw = G_FLOAT(OFS_PARM0);
1377 dist = G_FLOAT(OFS_PARM1);
1379 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1381 G_FLOAT(OFS_RETURN) = 0;
1385 yaw = yaw*M_PI*2 / 360;
1387 move[0] = cos(yaw)*dist;
1388 move[1] = sin(yaw)*dist;
1391 // save program state, because SV_movestep may call other progs
1392 oldf = pr_xfunction;
1393 oldself = pr_global_struct->self;
1395 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1398 // restore program state
1399 pr_xfunction = oldf;
1400 pr_global_struct->self = oldself;
1410 void PF_droptofloor (void)
1416 ent = PROG_TO_EDICT(pr_global_struct->self);
1418 VectorCopy (ent->v->origin, end);
1421 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1423 if (trace.fraction == 1)
1424 G_FLOAT(OFS_RETURN) = 0;
1427 VectorCopy (trace.endpos, ent->v->origin);
1428 SV_LinkEdict (ent, false);
1429 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1430 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1431 G_FLOAT(OFS_RETURN) = 1;
1432 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1433 ent->e->suspendedinairflag = true;
1441 void(float style, string value) lightstyle
1444 void PF_lightstyle (void)
1451 style = G_FLOAT(OFS_PARM0);
1452 val = G_STRING(OFS_PARM1);
1454 // change the string in sv
1455 sv.lightstyles[style] = val;
1457 // send message to all clients on this server
1458 if (sv.state != ss_active)
1461 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1462 if (client->active || client->spawned)
1464 MSG_WriteChar (&client->message, svc_lightstyle);
1465 MSG_WriteChar (&client->message,style);
1466 MSG_WriteString (&client->message, val);
1473 f = G_FLOAT(OFS_PARM0);
1475 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1477 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1479 void PF_floor (void)
1481 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1485 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1494 void PF_checkbottom (void)
1496 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1504 void PF_pointcontents (void)
1506 G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1513 entity nextent(entity)
1516 void PF_nextent (void)
1521 i = G_EDICTNUM(OFS_PARM0);
1524 pr_xfunction->builtinsprofile++;
1526 if (i == sv.num_edicts)
1528 RETURN_EDICT(sv.edicts);
1544 Pick a vector for the player to shoot along
1545 vector aim(entity, missilespeed)
1550 edict_t *ent, *check, *bestent;
1551 vec3_t start, dir, end, bestdir;
1554 float dist, bestdist;
1557 ent = G_EDICT(OFS_PARM0);
1558 speed = G_FLOAT(OFS_PARM1);
1560 VectorCopy (ent->v->origin, start);
1563 // try sending a trace straight
1564 VectorCopy (pr_global_struct->v_forward, dir);
1565 VectorMA (start, 2048, dir, end);
1566 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1567 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1568 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1570 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1575 // try all possible entities
1576 VectorCopy (dir, bestdir);
1577 bestdist = sv_aim.value;
1580 check = NEXT_EDICT(sv.edicts);
1581 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1583 pr_xfunction->builtinsprofile++;
1584 if (check->v->takedamage != DAMAGE_AIM)
1588 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1589 continue; // don't aim at teammate
1590 for (j=0 ; j<3 ; j++)
1591 end[j] = check->v->origin[j]
1592 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1593 VectorSubtract (end, start, dir);
1594 VectorNormalize (dir);
1595 dist = DotProduct (dir, pr_global_struct->v_forward);
1596 if (dist < bestdist)
1597 continue; // to far to turn
1598 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1599 if (tr.ent == check)
1600 { // can shoot at this one
1608 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1609 dist = DotProduct (dir, pr_global_struct->v_forward);
1610 VectorScale (pr_global_struct->v_forward, dist, end);
1612 VectorNormalize (end);
1613 VectorCopy (end, G_VECTOR(OFS_RETURN));
1617 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1625 This was a major timewaster in progs, so it was converted to C
1628 void PF_changeyaw (void)
1631 float ideal, current, move, speed;
1633 ent = PROG_TO_EDICT(pr_global_struct->self);
1634 current = ANGLEMOD(ent->v->angles[1]);
1635 ideal = ent->v->ideal_yaw;
1636 speed = ent->v->yaw_speed;
1638 if (current == ideal)
1640 move = ideal - current;
1641 if (ideal > current)
1662 ent->v->angles[1] = ANGLEMOD (current + move);
1670 void PF_changepitch (void)
1673 float ideal, current, move, speed;
1676 ent = G_EDICT(OFS_PARM0);
1677 current = ANGLEMOD( ent->v->angles[0] );
1678 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1679 ideal = val->_float;
1682 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1685 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1686 speed = val->_float;
1689 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1693 if (current == ideal)
1695 move = ideal - current;
1696 if (ideal > current)
1717 ent->v->angles[0] = ANGLEMOD (current + move);
1721 ===============================================================================
1725 ===============================================================================
1728 #define MSG_BROADCAST 0 // unreliable to all
1729 #define MSG_ONE 1 // reliable to one (msg_entity)
1730 #define MSG_ALL 2 // reliable to all
1731 #define MSG_INIT 3 // write to the init string
1733 sizebuf_t *WriteDest (void)
1739 dest = G_FLOAT(OFS_PARM0);
1743 return &sv.datagram;
1746 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1747 entnum = NUM_FOR_EDICT(ent);
1748 if (entnum < 1 || entnum > svs.maxclients)
1749 Host_Error ("WriteDest: not a client");
1750 return &svs.clients[entnum-1].message;
1753 return &sv.reliable_datagram;
1759 Host_Error ("WriteDest: bad destination");
1766 void PF_WriteByte (void)
1768 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1771 void PF_WriteChar (void)
1773 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1776 void PF_WriteShort (void)
1778 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1781 void PF_WriteLong (void)
1783 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1786 void PF_WriteAngle (void)
1788 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1791 void PF_WriteCoord (void)
1793 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1796 void PF_WriteString (void)
1798 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1802 void PF_WriteEntity (void)
1804 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1807 //=============================================================================
1809 void PF_makestatic (void)
1814 ent = G_EDICT(OFS_PARM0);
1817 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1822 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1823 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1824 MSG_WriteShort (&sv.signon, ent->v->frame);
1828 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1829 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1830 MSG_WriteByte (&sv.signon, ent->v->frame);
1833 MSG_WriteByte (&sv.signon, ent->v->colormap);
1834 MSG_WriteByte (&sv.signon, ent->v->skin);
1835 for (i=0 ; i<3 ; i++)
1837 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1838 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1841 // throw the entity away now
1845 //=============================================================================
1852 void PF_setspawnparms (void)
1858 ent = G_EDICT(OFS_PARM0);
1859 i = NUM_FOR_EDICT(ent);
1860 if (i < 1 || i > svs.maxclients)
1861 Host_Error ("Entity is not a client");
1863 // copy spawn parms out of the client_t
1864 client = svs.clients + (i-1);
1866 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1867 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1875 void PF_changelevel (void)
1879 // make sure we don't issue two changelevels
1880 if (svs.changelevel_issued)
1882 svs.changelevel_issued = true;
1884 s = G_STRING(OFS_PARM0);
1885 Cbuf_AddText (va("changelevel %s\n",s));
1890 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1895 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1900 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1907 Returns a vector of length < 1
1912 void PF_randomvec (void)
1917 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1918 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1919 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1921 while (DotProduct(temp, temp) >= 1);
1922 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1925 void SV_LightPoint (vec3_t color, vec3_t p);
1930 Returns a color vector indicating the lighting at the requested point.
1932 (Internal Operation note: actually measures the light beneath the point, just like
1933 the model lighting on the client)
1938 void PF_GetLight (void)
1942 p = G_VECTOR(OFS_PARM0);
1943 SV_LightPoint (color, p);
1944 VectorCopy (color, G_VECTOR(OFS_RETURN));
1947 #define MAX_QC_CVARS 128
1948 cvar_t qc_cvar[MAX_QC_CVARS];
1951 void PF_registercvar (void)
1955 name = G_STRING(OFS_PARM0);
1956 value = G_STRING(OFS_PARM1);
1957 G_FLOAT(OFS_RETURN) = 0;
1958 // first check to see if it has already been defined
1959 if (Cvar_FindVar (name))
1962 // check for overlap with a command
1963 if (Cmd_Exists (name))
1965 Con_Printf ("PF_registercvar: %s is a command\n", name);
1969 if (currentqc_cvar >= MAX_QC_CVARS)
1970 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1972 // copy the name and value
1973 variable = &qc_cvar[currentqc_cvar++];
1974 variable->name = Z_Malloc (strlen(name)+1);
1975 strcpy (variable->name, name);
1976 variable->string = Z_Malloc (strlen(value)+1);
1977 strcpy (variable->string, value);
1978 variable->value = atof (value);
1980 Cvar_RegisterVariable(variable);
1981 G_FLOAT(OFS_RETURN) = 1; // success
1988 returns the minimum of two supplied floats
1995 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1997 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1998 else if (pr_argc >= 3)
2001 float f = G_FLOAT(OFS_PARM0);
2002 for (i = 1;i < pr_argc;i++)
2003 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2004 f = G_FLOAT((OFS_PARM0+i*3));
2005 G_FLOAT(OFS_RETURN) = f;
2008 Host_Error("min: must supply at least 2 floats\n");
2015 returns the maximum of two supplied floats
2022 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2024 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2025 else if (pr_argc >= 3)
2028 float f = G_FLOAT(OFS_PARM0);
2029 for (i = 1;i < pr_argc;i++)
2030 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2031 f = G_FLOAT((OFS_PARM0+i*3));
2032 G_FLOAT(OFS_RETURN) = f;
2035 Host_Error("max: must supply at least 2 floats\n");
2042 returns number bounded by supplied range
2044 min(min, value, max)
2047 void PF_bound (void)
2049 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2056 returns a raised to power b
2063 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2070 copies data from one entity to another
2072 copyentity(src, dst)
2075 void PF_copyentity (void)
2078 in = G_EDICT(OFS_PARM0);
2079 out = G_EDICT(OFS_PARM1);
2080 memcpy(out->v, in->v, progs->entityfields * 4);
2087 sets the color of a client and broadcasts the update to all connected clients
2089 setcolor(clientent, value)
2092 void PF_setcolor (void)
2097 entnum = G_EDICTNUM(OFS_PARM0);
2098 i = G_FLOAT(OFS_PARM1);
2100 if (entnum < 1 || entnum > svs.maxclients)
2102 Con_Printf ("tried to setcolor a non-client\n");
2106 client = &svs.clients[entnum-1];
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->nummodelsurfaces)
2562 return model->surfaces + surfnum + model->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->nummodelsurfaces;surfnum++)
2648 surf = model->surfaces + surfnum + model->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)
2858 int end, start, length, slen;
2860 char string[MAX_VARSTRING];
2861 s = G_STRING(OFS_PARM0);
2862 start = G_FLOAT(OFS_PARM1);
2863 length = G_FLOAT(OFS_PARM2);
2870 if (length > slen - start)
2871 length = slen - start;
2872 if (length > MAX_VARSTRING - 1)
2873 length = MAX_VARSTRING - 1;
2877 memcpy(string, s + start, length);
2881 G_INT(OFS_RETURN) = PR_SetString(string);
2884 //vector(string s) stov = #117; // returns vector value from a string
2887 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2890 //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)
2891 void PF_strzone(void)
2894 in = G_STRING(OFS_PARM0);
2895 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2897 G_INT(OFS_RETURN) = PR_SetString(out);
2900 //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!!!)
2901 void PF_strunzone(void)
2903 Mem_Free(G_STRING(OFS_PARM0));
2906 builtin_t pr_builtin[] =
2909 PF_makevectors, // #1 void(entity e) makevectors
2910 PF_setorigin, // #2 void(entity e, vector o) setorigin
2911 PF_setmodel, // #3 void(entity e, string m) setmodel
2912 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2913 NULL, // #5 void(entity e, vector min, vector max) setabssize
2914 PF_break, // #6 void() break
2915 PF_random, // #7 float() random
2916 PF_sound, // #8 void(entity e, float chan, string samp) sound
2917 PF_normalize, // #9 vector(vector v) normalize
2918 PF_error, // #10 void(string e) error
2919 PF_objerror, // #11 void(string e) objerror
2920 PF_vlen, // #12 float(vector v) vlen
2921 PF_vectoyaw, // #13 float(vector v) vectoyaw
2922 PF_Spawn, // #14 entity() spawn
2923 PF_Remove, // #15 void(entity e) remove
2924 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2925 PF_checkclient, // #17 entity() clientlist
2926 PF_Find, // #18 entity(entity start, .string fld, string match) find
2927 PF_precache_sound, // #19 void(string s) precache_sound
2928 PF_precache_model, // #20 void(string s) precache_model
2929 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2930 PF_findradius, // #22 entity(vector org, float rad) findradius
2931 PF_bprint, // #23 void(string s) bprint
2932 PF_sprint, // #24 void(entity client, string s) sprint
2933 PF_dprint, // #25 void(string s) dprint
2934 PF_ftos, // #26 void(string s) ftos
2935 PF_vtos, // #27 void(string s) vtos
2936 PF_coredump, // #28 void() coredump
2937 PF_traceon, // #29 void() traceon
2938 PF_traceoff, // #30 void() traceoff
2939 PF_eprint, // #31 void(entity e) eprint
2940 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2942 PF_droptofloor, // #34 float() droptofloor
2943 PF_lightstyle, // #35 void(float style, string value) lightstyle
2944 PF_rint, // #36 float(float v) rint
2945 PF_floor, // #37 float(float v) floor
2946 PF_ceil, // #38 float(float v) ceil
2948 PF_checkbottom, // #40 float(entity e) checkbottom
2949 PF_pointcontents , // #41 float(vector v) pointcontents
2951 PF_fabs, // #43 float(float f) fabs
2952 PF_aim, // #44 vector(entity e, float speed) aim
2953 PF_cvar, // #45 float(string s) cvar
2954 PF_localcmd, // #46 void(string s) localcmd
2955 PF_nextent, // #47 entity(entity e) nextent
2956 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
2957 PF_changeyaw, // #49 void() ChangeYaw
2959 PF_vectoangles, // #51 vector(vector v) vectoangles
2960 PF_WriteByte, // #52 void(float to, float f) WriteByte
2961 PF_WriteChar, // #53 void(float to, float f) WriteChar
2962 PF_WriteShort, // #54 void(float to, float f) WriteShort
2963 PF_WriteLong, // #55 void(float to, float f) WriteLong
2964 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
2965 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
2966 PF_WriteString, // #58 void(float to, string s) WriteString
2967 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
2968 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2969 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2970 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2971 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2972 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2973 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2975 SV_MoveToGoal, // #67 void(float step) movetogoal
2976 PF_precache_file, // #68 string(string s) precache_file
2977 PF_makestatic, // #69 void(entity e) makestatic
2978 PF_changelevel, // #70 void(string s) changelevel
2980 PF_cvar_set, // #72 void(string var, string val) cvar_set
2981 PF_centerprint, // #73 void(entity client, strings) centerprint
2982 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2983 PF_precache_model, // #75 string(string s) precache_model2
2984 PF_precache_sound, // #76 string(string s) precache_sound2
2985 PF_precache_file, // #77 string(string s) precache_file2
2986 PF_setspawnparms, // #78 void(entity e) setspawnparms
2989 PF_stof, // #81 float(string s) stof (FRIK_FILE)
2998 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2999 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3000 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3001 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3002 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3003 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3004 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3005 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3006 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3007 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3018 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3019 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3020 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3021 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3022 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3023 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3024 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3025 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3026 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3027 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3028 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3029 a a a a a a a a // #120-199
3030 a a a a a a a a a a // #200-299
3031 a a a a a a a a a a // #300-399
3032 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3033 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3034 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3035 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3036 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3037 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3038 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3039 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3040 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3041 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3042 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3043 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3044 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3045 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3046 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3047 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3048 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3049 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3050 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3051 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3052 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3053 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3054 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3055 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3056 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3057 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3058 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3059 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3060 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3061 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3062 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3063 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3064 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3065 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3066 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3067 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3068 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3069 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3070 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3071 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3072 a a a a a a // #440-499 (LordHavoc)
3075 builtin_t *pr_builtins = pr_builtin;
3076 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3078 void PR_Cmd_Init(void)
3080 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3084 void PR_Cmd_Reset(void)
3086 Mem_EmptyPool(pr_strings_mempool);
3087 PR_Files_CloseAll();