2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
26 mempool_t *pr_strings_mempool;
28 #define MAX_VARSTRING 4096
30 char pr_varstring_temp[MAX_VARSTRING];
32 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
36 ===============================================================================
40 ===============================================================================
44 char *PF_VarString (int first)
50 out = pr_varstring_temp;
51 outend = pr_varstring_temp + sizeof(pr_varstring_temp) - 1;
52 for (i = first;i < pr_argc && out < outend;i++)
54 s = G_STRING((OFS_PARM0+i*3));
55 while (out < outend && *s)
59 return pr_varstring_temp;
62 char *ENGINE_EXTENSIONS =
72 "DP_ENT_CUSTOMCOLORMAP "
73 "DP_ENT_EXTERIORMODELTOCLIENT "
74 "DP_ENT_LOWPRECISION "
78 "DP_GFX_EXTERNALTEXTURES "
80 "DP_GFX_QUAKE3MODELTAGS "
84 "DP_HALFLIFE_MAP_CVAR "
87 "DP_MOVETYPEBOUNCEMISSILE "
93 "DP_QC_FINDCHAINFLOAT "
99 "DP_QC_SINCOSSQRTPOW "
102 "DP_QC_VECTORVECTORS "
108 "DP_SV_DRAWONLYTOCLIENT "
110 "DP_SV_EXTERIORMODELTOCLIENT "
111 "DP_SV_NODRAWTOCLIENT "
112 "DP_SV_PLAYERPHYSICS "
118 "DP_TE_EXPLOSIONRGB "
120 "DP_TE_PARTICLECUBE "
121 "DP_TE_PARTICLERAIN "
122 "DP_TE_PARTICLESNOW "
124 "DP_TE_QUADEFFECTS1 "
127 "DP_TE_STANDARDEFFECTBUILTINS "
130 "KRIMZON_SV_PARSECLIENTCOMMAND "
136 qboolean checkextension(char *name)
141 for (e = ENGINE_EXTENSIONS;*e;e++)
148 while (*e && *e != ' ')
150 if (e - start == len)
151 if (!strncasecmp(start, name, len))
161 returns true if the extension is supported by the server
163 checkextension(extensionname)
166 void PF_checkextension (void)
168 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
175 This is a TERMINAL error, which will kill off the entire server.
187 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
188 ed = PROG_TO_EDICT(pr_global_struct->self);
191 Host_Error ("Program error");
198 Dumps out self, then an error message. The program is aborted and self is
199 removed, but the level can continue.
204 void PF_objerror (void)
210 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
211 ed = PROG_TO_EDICT(pr_global_struct->self);
221 Writes new values for v_forward, v_up, and v_right based on angles
225 void PF_makevectors (void)
227 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
234 Writes new values for v_forward, v_up, and v_right based on the given forward vector
235 vectorvectors(vector, vector)
238 void PF_vectorvectors (void)
240 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
241 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
248 This is the only valid way to move an object without using the physics of the world (setting velocity and waiting). Directly changing origin will not set internal links correctly, so clipping would be messed up. This should be called when an object is spawned, and then only if it is teleported.
250 setorigin (entity, origin)
253 void PF_setorigin (void)
258 e = G_EDICT(OFS_PARM0);
259 org = G_VECTOR(OFS_PARM1);
260 VectorCopy (org, e->v->origin);
261 SV_LinkEdict (e, false);
265 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
269 for (i=0 ; i<3 ; i++)
271 Host_Error ("backwards mins/maxs");
273 // set derived values
274 VectorCopy (min, e->v->mins);
275 VectorCopy (max, e->v->maxs);
276 VectorSubtract (max, min, e->v->size);
278 SV_LinkEdict (e, false);
285 the size box is rotated by the current angle
286 LordHavoc: no it isn't...
288 setsize (entity, minvector, maxvector)
291 void PF_setsize (void)
296 e = G_EDICT(OFS_PARM0);
297 min = G_VECTOR(OFS_PARM1);
298 max = G_VECTOR(OFS_PARM2);
299 SetMinMaxSize (e, min, max, false);
307 setmodel(entity, model)
310 void PF_setmodel (void)
317 e = G_EDICT(OFS_PARM0);
318 m = G_STRING(OFS_PARM1);
320 // check to see if model was properly precached
321 for (i=0, check = sv.model_precache ; *check ; i++, check++)
322 if (!strcmp(*check, m))
326 Host_Error ("no precache: %s\n", m);
329 e->v->model = PR_SetString(*check);
330 e->v->modelindex = i;
332 mod = sv.models[ (int)e->v->modelindex];
335 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
337 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
344 broadcast print to everyone on server
349 void PF_bprint (void)
354 SV_BroadcastPrintf ("%s", s);
361 single print to a specific client
363 sprint(clientent, value)
366 void PF_sprint (void)
372 entnum = G_EDICTNUM(OFS_PARM0);
375 if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1])
377 Con_Printf ("tried to sprint to a non-client\n");
381 client = svs.connectedclients[entnum-1];
382 MSG_WriteChar(&client->message,svc_print);
383 MSG_WriteString(&client->message, s );
391 single print to a specific client
393 centerprint(clientent, value)
396 void PF_centerprint (void)
402 entnum = G_EDICTNUM(OFS_PARM0);
405 if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1])
407 Con_Printf ("tried to sprint to a non-client\n");
411 client = svs.connectedclients[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, 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)
829 // cycle to the next one
831 check = bound(1, check, MAX_SCOREBOARD);
832 if (check == MAX_SCOREBOARD)
840 pr_xfunction->builtinsprofile++;
842 if (i == MAX_SCOREBOARD+1)
844 // look up the client's edict
846 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
847 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
849 // found a valid client (possibly the same one again)
853 // get the PVS for the entity
854 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
855 memcpy (checkpvs, sv.worldmodel->brushq1.LeafPVS(sv.worldmodel, sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, org)), (sv.worldmodel->brushq1.numleafs+7)>>3 );
864 Returns a client (or object that has a client enemy) that would be a
867 If there is more than one valid option, they are cycled each frame
869 If (self.origin + self.viewofs) is not in the PVS of the current target,
870 it is not returned at all.
875 int c_invis, c_notvis;
876 void PF_checkclient (void)
883 // find a new check if on a new frame
884 if (sv.time - sv.lastchecktime >= 0.1)
886 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
887 sv.lastchecktime = sv.time;
890 // return check if it might be visible
891 ent = EDICT_NUM(sv.lastcheck);
892 if (ent->e->free || ent->v->health <= 0)
894 RETURN_EDICT(sv.edicts);
898 // if current entity can't possibly see the check entity, return 0
899 self = PROG_TO_EDICT(pr_global_struct->self);
900 VectorAdd (self->v->origin, self->v->view_ofs, view);
901 leaf = sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, view);
904 l = (leaf - sv.worldmodel->brushq1.leafs) - 1;
905 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
908 RETURN_EDICT(sv.edicts);
913 // might be able to see it
918 //============================================================================
925 Sends text over to the client's execution buffer
927 stuffcmd (clientent, value)
930 void PF_stuffcmd (void)
936 entnum = G_EDICTNUM(OFS_PARM0);
937 if (entnum < 1 || entnum > MAX_SCOREBOARD)
938 Host_Error ("Parm 0 not a client");
939 str = G_STRING(OFS_PARM1);
942 if ((host_client = svs.connectedclients[entnum-1]))
943 Host_ClientCommands ("%s", str);
951 Sends text over to the client's execution buffer
956 void PF_localcmd (void)
960 str = G_STRING(OFS_PARM0);
975 str = G_STRING(OFS_PARM0);
977 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
987 void PF_cvar_set (void)
991 var = G_STRING(OFS_PARM0);
992 val = G_STRING(OFS_PARM1);
1001 Returns a chain of entities that have origins within a spherical area
1003 findradius (origin, radius)
1006 void PF_findradius (void)
1008 edict_t *ent, *chain;
1015 chain = (edict_t *)sv.edicts;
1017 org = G_VECTOR(OFS_PARM0);
1018 radius = G_FLOAT(OFS_PARM1);
1019 radius2 = radius * radius;
1021 ent = NEXT_EDICT(sv.edicts);
1022 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1024 pr_xfunction->builtinsprofile++;
1027 if (ent->v->solid == SOLID_NOT)
1030 // LordHavoc: compare against bounding box rather than center,
1031 // and use DotProduct instead of Length, major speedup
1032 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1033 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1034 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1035 if (DotProduct(eorg, eorg) > radius2)
1038 ent->v->chain = EDICT_TO_PROG(chain);
1042 RETURN_EDICT(chain);
1051 void PF_dprint (void)
1053 Con_DPrintf ("%s",PF_VarString(0));
1056 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1057 #define STRINGTEMP_BUFFERS 16
1058 #define STRINGTEMP_LENGTH 128
1059 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1060 static int pr_string_tempindex = 0;
1062 static char *PR_GetTempString(void)
1065 s = pr_string_temp[pr_string_tempindex];
1066 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1074 v = G_FLOAT(OFS_PARM0);
1076 s = PR_GetTempString();
1077 // LordHavoc: ftos improvement
1078 sprintf (s, "%g", v);
1079 G_INT(OFS_RETURN) = PR_SetString(s);
1085 v = G_FLOAT(OFS_PARM0);
1086 G_FLOAT(OFS_RETURN) = fabs(v);
1092 s = PR_GetTempString();
1093 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1094 G_INT(OFS_RETURN) = PR_SetString(s);
1100 s = PR_GetTempString();
1101 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1102 G_INT(OFS_RETURN) = PR_SetString(s);
1105 void PF_Spawn (void)
1108 pr_xfunction->builtinsprofile += 20;
1113 void PF_Remove (void)
1116 pr_xfunction->builtinsprofile += 20;
1118 ed = G_EDICT(OFS_PARM0);
1119 if (ed == sv.edicts)
1120 Host_Error("remove: tried to remove world\n");
1121 if (NUM_FOR_EDICT(ed) <= MAX_SCOREBOARD)
1122 Host_Error("remove: tried to remove a client\n");
1127 // entity (entity start, .string field, string match) find = #5;
1135 e = G_EDICTNUM(OFS_PARM0);
1136 f = G_INT(OFS_PARM1);
1137 s = G_STRING(OFS_PARM2);
1140 RETURN_EDICT(sv.edicts);
1144 for (e++ ; e < sv.num_edicts ; e++)
1146 pr_xfunction->builtinsprofile++;
1160 RETURN_EDICT(sv.edicts);
1163 // LordHavoc: added this for searching float, int, and entity reference fields
1164 void PF_FindFloat (void)
1171 e = G_EDICTNUM(OFS_PARM0);
1172 f = G_INT(OFS_PARM1);
1173 s = G_FLOAT(OFS_PARM2);
1175 for (e++ ; e < sv.num_edicts ; e++)
1177 pr_xfunction->builtinsprofile++;
1181 if (E_FLOAT(ed,f) == s)
1188 RETURN_EDICT(sv.edicts);
1191 // chained search for strings in entity fields
1192 // entity(.string field, string match) findchain = #402;
1193 void PF_findchain (void)
1198 edict_t *ent, *chain;
1200 chain = (edict_t *)sv.edicts;
1202 f = G_INT(OFS_PARM0);
1203 s = G_STRING(OFS_PARM1);
1206 RETURN_EDICT(sv.edicts);
1210 ent = NEXT_EDICT(sv.edicts);
1211 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1213 pr_xfunction->builtinsprofile++;
1216 t = E_STRING(ent,f);
1222 ent->v->chain = EDICT_TO_PROG(chain);
1226 RETURN_EDICT(chain);
1229 // LordHavoc: chained search for float, int, and entity reference fields
1230 // entity(.string field, float match) findchainfloat = #403;
1231 void PF_findchainfloat (void)
1236 edict_t *ent, *chain;
1238 chain = (edict_t *)sv.edicts;
1240 f = G_INT(OFS_PARM0);
1241 s = G_FLOAT(OFS_PARM1);
1243 ent = NEXT_EDICT(sv.edicts);
1244 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1246 pr_xfunction->builtinsprofile++;
1249 if (E_FLOAT(ent,f) != s)
1252 ent->v->chain = EDICT_TO_PROG(chain);
1256 RETURN_EDICT(chain);
1259 void PR_CheckEmptyString (char *s)
1262 Host_Error ("Bad string");
1265 void PF_precache_file (void)
1266 { // precache_file is only used to copy files with qcc, it does nothing
1267 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1270 void PF_precache_sound (void)
1275 if (sv.state != ss_loading)
1276 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1278 s = G_STRING(OFS_PARM0);
1279 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1280 PR_CheckEmptyString (s);
1282 for (i=0 ; i<MAX_SOUNDS ; i++)
1284 if (!sv.sound_precache[i])
1286 sv.sound_precache[i] = s;
1289 if (!strcmp(sv.sound_precache[i], s))
1292 Host_Error ("PF_precache_sound: overflow");
1295 void PF_precache_model (void)
1300 if (sv.state != ss_loading)
1301 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1303 s = G_STRING(OFS_PARM0);
1304 if (sv.worldmodel->brushq1.ishlbsp && ((!s) || (!s[0])))
1306 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1307 PR_CheckEmptyString (s);
1309 for (i=0 ; i<MAX_MODELS ; i++)
1311 if (!sv.model_precache[i])
1313 sv.model_precache[i] = s;
1314 sv.models[i] = Mod_ForName (s, true, false, false);
1317 if (!strcmp(sv.model_precache[i], s))
1320 Host_Error ("PF_precache_model: overflow");
1324 void PF_coredump (void)
1329 void PF_traceon (void)
1334 void PF_traceoff (void)
1339 void PF_eprint (void)
1341 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1348 float(float yaw, float dist) walkmove
1351 void PF_walkmove (void)
1359 ent = PROG_TO_EDICT(pr_global_struct->self);
1360 yaw = G_FLOAT(OFS_PARM0);
1361 dist = G_FLOAT(OFS_PARM1);
1363 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1365 G_FLOAT(OFS_RETURN) = 0;
1369 yaw = yaw*M_PI*2 / 360;
1371 move[0] = cos(yaw)*dist;
1372 move[1] = sin(yaw)*dist;
1375 // save program state, because SV_movestep may call other progs
1376 oldf = pr_xfunction;
1377 oldself = pr_global_struct->self;
1379 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1382 // restore program state
1383 pr_xfunction = oldf;
1384 pr_global_struct->self = oldself;
1394 void PF_droptofloor (void)
1400 ent = PROG_TO_EDICT(pr_global_struct->self);
1402 VectorCopy (ent->v->origin, end);
1405 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1407 if (trace.fraction == 1)
1408 G_FLOAT(OFS_RETURN) = 0;
1411 VectorCopy (trace.endpos, ent->v->origin);
1412 SV_LinkEdict (ent, false);
1413 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1414 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1415 G_FLOAT(OFS_RETURN) = 1;
1416 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1417 ent->e->suspendedinairflag = true;
1425 void(float style, string value) lightstyle
1428 void PF_lightstyle (void)
1435 style = G_FLOAT(OFS_PARM0);
1436 val = G_STRING(OFS_PARM1);
1438 // change the string in sv
1439 sv.lightstyles[style] = val;
1441 // send message to all clients on this server
1442 if (sv.state != ss_active)
1445 for (j = 0;j < MAX_SCOREBOARD;j++)
1447 if ((client = svs.connectedclients[j]))
1449 MSG_WriteChar (&client->message, svc_lightstyle);
1450 MSG_WriteChar (&client->message,style);
1451 MSG_WriteString (&client->message, val);
1459 f = G_FLOAT(OFS_PARM0);
1461 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1463 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1465 void PF_floor (void)
1467 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1471 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1480 void PF_checkbottom (void)
1482 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1490 void PF_pointcontents (void)
1492 G_FLOAT(OFS_RETURN) = SV_PointContents(G_VECTOR(OFS_PARM0));
1499 entity nextent(entity)
1502 void PF_nextent (void)
1507 i = G_EDICTNUM(OFS_PARM0);
1510 pr_xfunction->builtinsprofile++;
1512 if (i == sv.num_edicts)
1514 RETURN_EDICT(sv.edicts);
1530 Pick a vector for the player to shoot along
1531 vector aim(entity, missilespeed)
1536 edict_t *ent, *check, *bestent;
1537 vec3_t start, dir, end, bestdir;
1540 float dist, bestdist;
1543 ent = G_EDICT(OFS_PARM0);
1544 speed = G_FLOAT(OFS_PARM1);
1546 VectorCopy (ent->v->origin, start);
1549 // try sending a trace straight
1550 VectorCopy (pr_global_struct->v_forward, dir);
1551 VectorMA (start, 2048, dir, end);
1552 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1553 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1554 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1556 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1561 // try all possible entities
1562 VectorCopy (dir, bestdir);
1563 bestdist = sv_aim.value;
1566 check = NEXT_EDICT(sv.edicts);
1567 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1569 pr_xfunction->builtinsprofile++;
1570 if (check->v->takedamage != DAMAGE_AIM)
1574 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1575 continue; // don't aim at teammate
1576 for (j=0 ; j<3 ; j++)
1577 end[j] = check->v->origin[j]
1578 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1579 VectorSubtract (end, start, dir);
1580 VectorNormalize (dir);
1581 dist = DotProduct (dir, pr_global_struct->v_forward);
1582 if (dist < bestdist)
1583 continue; // to far to turn
1584 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1585 if (tr.ent == check)
1586 { // can shoot at this one
1594 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1595 dist = DotProduct (dir, pr_global_struct->v_forward);
1596 VectorScale (pr_global_struct->v_forward, dist, end);
1598 VectorNormalize (end);
1599 VectorCopy (end, G_VECTOR(OFS_RETURN));
1603 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1611 This was a major timewaster in progs, so it was converted to C
1614 void PF_changeyaw (void)
1617 float ideal, current, move, speed;
1619 ent = PROG_TO_EDICT(pr_global_struct->self);
1620 current = ANGLEMOD(ent->v->angles[1]);
1621 ideal = ent->v->ideal_yaw;
1622 speed = ent->v->yaw_speed;
1624 if (current == ideal)
1626 move = ideal - current;
1627 if (ideal > current)
1648 ent->v->angles[1] = ANGLEMOD (current + move);
1656 void PF_changepitch (void)
1659 float ideal, current, move, speed;
1662 ent = G_EDICT(OFS_PARM0);
1663 current = ANGLEMOD( ent->v->angles[0] );
1664 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1665 ideal = val->_float;
1668 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1671 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1672 speed = val->_float;
1675 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1679 if (current == ideal)
1681 move = ideal - current;
1682 if (ideal > current)
1703 ent->v->angles[0] = ANGLEMOD (current + move);
1707 ===============================================================================
1711 ===============================================================================
1714 #define MSG_BROADCAST 0 // unreliable to all
1715 #define MSG_ONE 1 // reliable to one (msg_entity)
1716 #define MSG_ALL 2 // reliable to all
1717 #define MSG_INIT 3 // write to the init string
1719 sizebuf_t *WriteDest (void)
1725 dest = G_FLOAT(OFS_PARM0);
1729 return &sv.datagram;
1732 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1733 entnum = NUM_FOR_EDICT(ent);
1734 if (entnum < 1 || entnum > MAX_SCOREBOARD || svs.connectedclients[entnum-1] == NULL)
1735 Host_Error("WriteDest: not a client");
1736 return &svs.connectedclients[entnum-1]->message;
1739 return &sv.reliable_datagram;
1745 Host_Error ("WriteDest: bad destination");
1752 void PF_WriteByte (void)
1754 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1757 void PF_WriteChar (void)
1759 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1762 void PF_WriteShort (void)
1764 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1767 void PF_WriteLong (void)
1769 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1772 void PF_WriteAngle (void)
1774 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1777 void PF_WriteCoord (void)
1779 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1782 void PF_WriteString (void)
1784 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1788 void PF_WriteEntity (void)
1790 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1793 //=============================================================================
1795 void PF_makestatic (void)
1800 ent = G_EDICT(OFS_PARM0);
1803 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1808 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1809 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1810 MSG_WriteShort (&sv.signon, ent->v->frame);
1814 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1815 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1816 MSG_WriteByte (&sv.signon, ent->v->frame);
1819 MSG_WriteByte (&sv.signon, ent->v->colormap);
1820 MSG_WriteByte (&sv.signon, ent->v->skin);
1821 for (i=0 ; i<3 ; i++)
1823 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1824 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1827 // throw the entity away now
1831 //=============================================================================
1838 void PF_setspawnparms (void)
1844 ent = G_EDICT(OFS_PARM0);
1845 i = NUM_FOR_EDICT(ent);
1846 if (i < 1 || i > MAX_SCOREBOARD || !(client = svs.connectedclients[i-1]))
1847 Host_Error ("Entity is not a client");
1849 // copy spawn parms out of the client_t
1850 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1851 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1859 void PF_changelevel (void)
1863 // make sure we don't issue two changelevels
1864 if (svs.changelevel_issued)
1866 svs.changelevel_issued = true;
1868 s = G_STRING(OFS_PARM0);
1869 Cbuf_AddText (va("changelevel %s\n",s));
1874 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1879 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1884 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1891 Returns a vector of length < 1
1896 void PF_randomvec (void)
1901 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1902 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1903 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1905 while (DotProduct(temp, temp) >= 1);
1906 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1909 void SV_LightPoint (vec3_t color, vec3_t p);
1914 Returns a color vector indicating the lighting at the requested point.
1916 (Internal Operation note: actually measures the light beneath the point, just like
1917 the model lighting on the client)
1922 void PF_GetLight (void)
1926 p = G_VECTOR(OFS_PARM0);
1927 SV_LightPoint (color, p);
1928 VectorCopy (color, G_VECTOR(OFS_RETURN));
1931 #define MAX_QC_CVARS 128
1932 cvar_t qc_cvar[MAX_QC_CVARS];
1935 void PF_registercvar (void)
1939 name = G_STRING(OFS_PARM0);
1940 value = G_STRING(OFS_PARM1);
1941 G_FLOAT(OFS_RETURN) = 0;
1942 // first check to see if it has already been defined
1943 if (Cvar_FindVar (name))
1946 // check for overlap with a command
1947 if (Cmd_Exists (name))
1949 Con_Printf ("PF_registercvar: %s is a command\n", name);
1953 if (currentqc_cvar >= MAX_QC_CVARS)
1954 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1956 // copy the name and value
1957 variable = &qc_cvar[currentqc_cvar++];
1958 variable->name = Z_Malloc (strlen(name)+1);
1959 strcpy (variable->name, name);
1960 variable->string = Z_Malloc (strlen(value)+1);
1961 strcpy (variable->string, value);
1962 variable->value = atof (value);
1964 Cvar_RegisterVariable(variable);
1965 G_FLOAT(OFS_RETURN) = 1; // success
1972 returns the minimum of two supplied floats
1979 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1981 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1982 else if (pr_argc >= 3)
1985 float f = G_FLOAT(OFS_PARM0);
1986 for (i = 1;i < pr_argc;i++)
1987 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1988 f = G_FLOAT((OFS_PARM0+i*3));
1989 G_FLOAT(OFS_RETURN) = f;
1992 Host_Error("min: must supply at least 2 floats\n");
1999 returns the maximum of two supplied floats
2006 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2008 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2009 else if (pr_argc >= 3)
2012 float f = G_FLOAT(OFS_PARM0);
2013 for (i = 1;i < pr_argc;i++)
2014 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2015 f = G_FLOAT((OFS_PARM0+i*3));
2016 G_FLOAT(OFS_RETURN) = f;
2019 Host_Error("max: must supply at least 2 floats\n");
2026 returns number bounded by supplied range
2028 min(min, value, max)
2031 void PF_bound (void)
2033 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2040 returns a raised to power b
2047 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2054 copies data from one entity to another
2056 copyentity(src, dst)
2059 void PF_copyentity (void)
2062 in = G_EDICT(OFS_PARM0);
2063 out = G_EDICT(OFS_PARM1);
2064 memcpy(out->v, in->v, progs->entityfields * 4);
2071 sets the color of a client and broadcasts the update to all connected clients
2073 setcolor(clientent, value)
2076 void PF_setcolor (void)
2082 entnum = G_EDICTNUM(OFS_PARM0);
2083 i = G_FLOAT(OFS_PARM1);
2085 if (entnum < 1 || entnum > MAX_SCOREBOARD || !(client = svs.connectedclients[entnum-1]))
2087 Con_Printf ("tried to setcolor a non-client\n");
2091 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2094 client->old_colors = i;
2095 client->edict->v->team = (i & 15) + 1;
2097 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2098 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2099 MSG_WriteByte (&sv.reliable_datagram, i);
2106 effect(origin, modelname, startframe, framecount, framerate)
2109 void PF_effect (void)
2112 s = G_STRING(OFS_PARM1);
2114 Host_Error("effect: no model specified\n");
2116 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2119 void PF_te_blood (void)
2121 if (G_FLOAT(OFS_PARM2) < 1)
2123 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2124 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2126 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2127 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2128 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2130 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2131 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2132 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2134 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2137 void PF_te_bloodshower (void)
2139 if (G_FLOAT(OFS_PARM3) < 1)
2141 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2142 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2144 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2145 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2146 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2148 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2149 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2150 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2152 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2154 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2157 void PF_te_explosionrgb (void)
2159 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2160 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2162 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2163 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2164 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2166 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2167 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2168 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2171 void PF_te_particlecube (void)
2173 if (G_FLOAT(OFS_PARM3) < 1)
2175 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2176 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2179 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2180 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2184 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2186 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2190 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2192 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2193 // gravity true/false
2194 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2196 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2199 void PF_te_particlerain (void)
2201 if (G_FLOAT(OFS_PARM3) < 1)
2203 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2204 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2206 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2207 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2208 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2218 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2220 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2223 void PF_te_particlesnow (void)
2225 if (G_FLOAT(OFS_PARM3) < 1)
2227 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2228 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2231 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2232 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2242 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2244 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2247 void PF_te_spark (void)
2249 if (G_FLOAT(OFS_PARM2) < 1)
2251 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2252 MSG_WriteByte(&sv.datagram, TE_SPARK);
2254 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2255 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2256 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2258 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2259 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2260 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2262 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2265 void PF_te_gunshotquad (void)
2267 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2268 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2270 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2271 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2272 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2275 void PF_te_spikequad (void)
2277 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2280 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2285 void PF_te_superspikequad (void)
2287 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2288 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2290 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2292 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2295 void PF_te_explosionquad (void)
2297 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2298 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2300 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2301 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2302 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2305 void PF_te_smallflash (void)
2307 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2308 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2310 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2312 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2315 void PF_te_customflash (void)
2317 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2319 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2320 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2322 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2323 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2324 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2326 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2328 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2330 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2331 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2332 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2335 void PF_te_gunshot (void)
2337 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2338 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2340 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2341 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2342 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2345 void PF_te_spike (void)
2347 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2350 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2355 void PF_te_superspike (void)
2357 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2358 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2360 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2365 void PF_te_explosion (void)
2367 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2368 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2370 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2375 void PF_te_tarexplosion (void)
2377 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2378 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2380 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2381 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2382 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2385 void PF_te_wizspike (void)
2387 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2388 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2390 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2392 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2395 void PF_te_knightspike (void)
2397 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2398 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2400 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2402 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2405 void PF_te_lavasplash (void)
2407 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2408 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2410 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2415 void PF_te_teleport (void)
2417 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2420 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2425 void PF_te_explosion2 (void)
2427 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2428 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2430 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2434 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2437 void PF_te_lightning1 (void)
2439 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2440 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2442 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2445 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2446 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2448 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2453 void PF_te_lightning2 (void)
2455 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2456 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2458 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2465 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2466 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2469 void PF_te_lightning3 (void)
2471 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2472 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2474 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2477 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2478 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2485 void PF_te_beam (void)
2487 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2488 MSG_WriteByte(&sv.datagram, TE_BEAM);
2490 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2501 void PF_te_plasmaburn (void)
2503 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2504 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2505 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2510 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2513 vec3_t v1, clipplanenormal, normal;
2514 vec_t clipplanedist, clipdist;
2516 if (surf->flags & SURF_PLANEBACK)
2517 VectorNegate(surf->plane->normal, normal);
2519 VectorCopy(surf->plane->normal, normal);
2520 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2522 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2523 VectorNormalizeFast(v1);
2524 CrossProduct(v1, normal, clipplanenormal);
2525 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2526 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2529 clipdist = -clipdist;
2530 VectorMA(out, clipdist, clipplanenormal, out);
2535 static msurface_t *getsurface(edict_t *ed, int surfnum)
2539 if (!ed || ed->e->free)
2541 modelindex = ed->v->modelindex;
2542 if (modelindex < 1 || modelindex >= MAX_MODELS)
2544 model = sv.models[modelindex];
2545 if (model->type != mod_brush)
2547 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2549 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2553 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2554 void PF_getsurfacenumpoints(void)
2557 // return 0 if no such surface
2558 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2560 G_FLOAT(OFS_RETURN) = 0;
2564 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2566 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2567 void PF_getsurfacepoint(void)
2572 VectorClear(G_VECTOR(OFS_RETURN));
2573 ed = G_EDICT(OFS_PARM0);
2574 if (!ed || ed->e->free)
2576 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2578 pointnum = G_FLOAT(OFS_PARM2);
2579 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2581 // FIXME: implement rotation/scaling
2582 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2584 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2585 void PF_getsurfacenormal(void)
2588 VectorClear(G_VECTOR(OFS_RETURN));
2589 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2591 // FIXME: implement rotation/scaling
2592 if (surf->flags & SURF_PLANEBACK)
2593 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2595 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2597 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2598 void PF_getsurfacetexture(void)
2601 G_INT(OFS_RETURN) = 0;
2602 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2604 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2606 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2607 void PF_getsurfacenearpoint(void)
2609 int surfnum, best, modelindex;
2611 vec_t dist, bestdist;
2616 G_FLOAT(OFS_RETURN) = -1;
2617 ed = G_EDICT(OFS_PARM0);
2618 point = G_VECTOR(OFS_PARM1);
2620 if (!ed || ed->e->free)
2622 modelindex = ed->v->modelindex;
2623 if (modelindex < 1 || modelindex >= MAX_MODELS)
2625 model = sv.models[modelindex];
2626 if (model->type != mod_brush)
2629 // FIXME: implement rotation/scaling
2630 VectorSubtract(point, ed->v->origin, p);
2632 bestdist = 1000000000;
2633 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2635 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2636 dist = PlaneDiff(p, surf->plane);
2638 if (dist < bestdist)
2640 clippointtosurface(surf, p, clipped);
2641 VectorSubtract(clipped, p, clipped);
2642 dist += DotProduct(clipped, clipped);
2643 if (dist < bestdist)
2650 G_FLOAT(OFS_RETURN) = best;
2652 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2653 void PF_getsurfaceclippedpoint(void)
2658 VectorClear(G_VECTOR(OFS_RETURN));
2659 ed = G_EDICT(OFS_PARM0);
2660 if (!ed || ed->e->free)
2662 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2664 // FIXME: implement rotation/scaling
2665 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2666 clippointtosurface(surf, p, out);
2667 // FIXME: implement rotation/scaling
2668 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2671 #define MAX_PRFILES 256
2673 qfile_t *pr_files[MAX_PRFILES];
2675 void PR_Files_Init(void)
2677 memset(pr_files, 0, sizeof(pr_files));
2680 void PR_Files_CloseAll(void)
2683 for (i = 0;i < MAX_PRFILES;i++)
2686 FS_Close(pr_files[i]);
2691 //float(string s) stof = #81; // get numerical value from a string
2694 char *s = PF_VarString(0);
2695 G_FLOAT(OFS_RETURN) = atof(s);
2698 //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
2702 char *modestring, *filename;
2703 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2704 if (pr_files[filenum] == NULL)
2706 if (filenum >= MAX_PRFILES)
2708 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2709 G_FLOAT(OFS_RETURN) = -2;
2712 mode = G_FLOAT(OFS_PARM1);
2715 case 0: // FILE_READ
2718 case 1: // FILE_APPEND
2721 case 2: // FILE_WRITE
2725 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2726 G_FLOAT(OFS_RETURN) = -3;
2729 filename = G_STRING(OFS_PARM0);
2730 // .. is parent directory on many platforms
2731 // / is parent directory on Amiga
2732 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2733 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2734 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2736 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2737 G_FLOAT(OFS_RETURN) = -4;
2740 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2741 if (pr_files[filenum] == NULL)
2742 G_FLOAT(OFS_RETURN) = -1;
2744 G_FLOAT(OFS_RETURN) = filenum;
2747 //void(float fhandle) fclose = #111; // closes a file
2748 void PF_fclose(void)
2750 int filenum = G_FLOAT(OFS_PARM0);
2751 if (filenum < 0 || filenum >= MAX_PRFILES)
2753 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2756 if (pr_files[filenum] == NULL)
2758 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2761 FS_Close(pr_files[filenum]);
2762 pr_files[filenum] = NULL;
2765 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2769 static char string[MAX_VARSTRING];
2770 int filenum = G_FLOAT(OFS_PARM0);
2771 if (filenum < 0 || filenum >= MAX_PRFILES)
2773 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2776 if (pr_files[filenum] == NULL)
2778 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2784 c = FS_Getc(pr_files[filenum]);
2785 if (c == '\r' || c == '\n' || c < 0)
2787 if (end < MAX_VARSTRING - 1)
2791 // remove \n following \r
2793 c = FS_Getc(pr_files[filenum]);
2794 if (developer.integer)
2795 Con_Printf("fgets: %s\n", string);
2797 G_INT(OFS_RETURN) = PR_SetString(string);
2799 G_INT(OFS_RETURN) = 0;
2802 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2806 char *s = PF_VarString(1);
2807 int filenum = G_FLOAT(OFS_PARM0);
2808 if (filenum < 0 || filenum >= MAX_PRFILES)
2810 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2813 if (pr_files[filenum] == NULL)
2815 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2818 if ((stringlength = strlen(s)))
2819 FS_Write(pr_files[filenum], s, stringlength);
2820 if (developer.integer)
2821 Con_Printf("fputs: %s\n", s);
2824 //float(string s) strlen = #114; // returns how many characters are in a string
2825 void PF_strlen(void)
2828 s = G_STRING(OFS_PARM0);
2830 G_FLOAT(OFS_RETURN) = strlen(s);
2832 G_FLOAT(OFS_RETURN) = 0;
2835 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2836 void PF_strcat(void)
2838 char *s = PF_VarString(0);
2839 G_INT(OFS_RETURN) = PR_SetString(s);
2842 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2843 void PF_substring(void)
2845 int i, start, length;
2846 char *s, *string = PR_GetTempString();
2847 s = G_STRING(OFS_PARM0);
2848 start = G_FLOAT(OFS_PARM1);
2849 length = G_FLOAT(OFS_PARM2);
2852 for (i = 0;i < start && *s;i++, s++);
2853 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2856 G_INT(OFS_RETURN) = PR_SetString(string);
2859 //vector(string s) stov = #117; // returns vector value from a string
2862 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2865 //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)
2866 void PF_strzone(void)
2869 in = G_STRING(OFS_PARM0);
2870 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2872 G_INT(OFS_RETURN) = PR_SetString(out);
2875 //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!!!)
2876 void PF_strunzone(void)
2878 Mem_Free(G_STRING(OFS_PARM0));
2881 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2882 //this function originally written by KrimZon, made shorter by LordHavoc
2883 void PF_clientcommand (void)
2885 client_t *temp_client;
2888 //find client for this entity
2889 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2890 if (i < 0 || i >= MAX_SCOREBOARD || !svs.connectedclients[i])
2891 Host_Error("PF_clientcommand: entity is not a client");
2893 temp_client = host_client;
2894 host_client = svs.connectedclients[i];
2895 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2896 host_client = temp_client;
2899 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2900 //this function originally written by KrimZon, made shorter by LordHavoc
2901 char **tokens = NULL;
2902 int max_tokens, num_tokens = 0;
2903 void PF_tokenize (void)
2907 str = G_STRING(OFS_PARM0);
2912 for (i=0;i<num_tokens;i++)
2918 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2919 max_tokens = strlen(str);
2921 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2923 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2924 strcpy(tokens[num_tokens], com_token);
2927 G_FLOAT(OFS_RETURN) = num_tokens;
2930 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2931 //this function originally written by KrimZon, made shorter by LordHavoc
2934 int token_num = G_FLOAT(OFS_PARM0);
2935 if (token_num >= 0 && token_num < num_tokens)
2936 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2938 G_INT(OFS_RETURN) = PR_SetString("");
2941 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
2942 void PF_setattachment (void)
2944 edict_t *e = G_EDICT(OFS_PARM0);
2945 edict_t *tagentity = G_EDICT(OFS_PARM1);
2946 char *tagname = G_STRING(OFS_PARM2);
2951 if (tagentity == NULL)
2952 tagentity = sv.edicts;
2954 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2956 v->edict = EDICT_TO_PROG(tagentity);
2958 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2961 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2963 modelindex = (int)tagentity->v->modelindex;
2964 if (modelindex >= 0 && modelindex < MAX_MODELS)
2966 model = sv.models[modelindex];
2967 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2968 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2969 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2971 if (v->_float == 0 && model->alias.aliasnum_tags)
2972 for (i = 0;i < model->alias.aliasnum_tags;i++)
2973 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2976 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
2979 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
2984 builtin_t pr_builtin[] =
2987 PF_makevectors, // #1 void(entity e) makevectors
2988 PF_setorigin, // #2 void(entity e, vector o) setorigin
2989 PF_setmodel, // #3 void(entity e, string m) setmodel
2990 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2991 NULL, // #5 void(entity e, vector min, vector max) setabssize
2992 PF_break, // #6 void() break
2993 PF_random, // #7 float() random
2994 PF_sound, // #8 void(entity e, float chan, string samp) sound
2995 PF_normalize, // #9 vector(vector v) normalize
2996 PF_error, // #10 void(string e) error
2997 PF_objerror, // #11 void(string e) objerror
2998 PF_vlen, // #12 float(vector v) vlen
2999 PF_vectoyaw, // #13 float(vector v) vectoyaw
3000 PF_Spawn, // #14 entity() spawn
3001 PF_Remove, // #15 void(entity e) remove
3002 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3003 PF_checkclient, // #17 entity() clientlist
3004 PF_Find, // #18 entity(entity start, .string fld, string match) find
3005 PF_precache_sound, // #19 void(string s) precache_sound
3006 PF_precache_model, // #20 void(string s) precache_model
3007 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3008 PF_findradius, // #22 entity(vector org, float rad) findradius
3009 PF_bprint, // #23 void(string s) bprint
3010 PF_sprint, // #24 void(entity client, string s) sprint
3011 PF_dprint, // #25 void(string s) dprint
3012 PF_ftos, // #26 void(string s) ftos
3013 PF_vtos, // #27 void(string s) vtos
3014 PF_coredump, // #28 void() coredump
3015 PF_traceon, // #29 void() traceon
3016 PF_traceoff, // #30 void() traceoff
3017 PF_eprint, // #31 void(entity e) eprint
3018 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3020 PF_droptofloor, // #34 float() droptofloor
3021 PF_lightstyle, // #35 void(float style, string value) lightstyle
3022 PF_rint, // #36 float(float v) rint
3023 PF_floor, // #37 float(float v) floor
3024 PF_ceil, // #38 float(float v) ceil
3026 PF_checkbottom, // #40 float(entity e) checkbottom
3027 PF_pointcontents , // #41 float(vector v) pointcontents
3029 PF_fabs, // #43 float(float f) fabs
3030 PF_aim, // #44 vector(entity e, float speed) aim
3031 PF_cvar, // #45 float(string s) cvar
3032 PF_localcmd, // #46 void(string s) localcmd
3033 PF_nextent, // #47 entity(entity e) nextent
3034 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3035 PF_changeyaw, // #49 void() ChangeYaw
3037 PF_vectoangles, // #51 vector(vector v) vectoangles
3038 PF_WriteByte, // #52 void(float to, float f) WriteByte
3039 PF_WriteChar, // #53 void(float to, float f) WriteChar
3040 PF_WriteShort, // #54 void(float to, float f) WriteShort
3041 PF_WriteLong, // #55 void(float to, float f) WriteLong
3042 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3043 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3044 PF_WriteString, // #58 void(float to, string s) WriteString
3045 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3046 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3047 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3048 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3049 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3050 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3051 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3053 SV_MoveToGoal, // #67 void(float step) movetogoal
3054 PF_precache_file, // #68 string(string s) precache_file
3055 PF_makestatic, // #69 void(entity e) makestatic
3056 PF_changelevel, // #70 void(string s) changelevel
3058 PF_cvar_set, // #72 void(string var, string val) cvar_set
3059 PF_centerprint, // #73 void(entity client, strings) centerprint
3060 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3061 PF_precache_model, // #75 string(string s) precache_model2
3062 PF_precache_sound, // #76 string(string s) precache_sound2
3063 PF_precache_file, // #77 string(string s) precache_file2
3064 PF_setspawnparms, // #78 void(entity e) setspawnparms
3067 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3076 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3077 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3078 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3079 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3080 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3081 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3082 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3083 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3084 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3085 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3096 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3097 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3098 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3099 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3100 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3101 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3102 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3103 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3104 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3105 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3106 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3107 a a a a a a a a // #120-199
3108 a a a a a a a a a a // #200-299
3109 a a a a a a a a a a // #300-399
3110 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3111 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3112 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3113 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3114 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3115 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3116 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3117 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3118 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3119 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3120 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3121 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3122 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3123 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3124 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3125 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3126 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3127 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3128 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3129 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3130 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3131 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3132 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3133 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3134 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3135 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3136 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3137 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3138 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3139 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3140 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3141 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3142 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3143 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3144 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3145 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3146 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3147 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3148 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3149 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3150 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3151 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3152 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3153 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3160 a a a a a // #450-499 (LordHavoc)
3163 builtin_t *pr_builtins = pr_builtin;
3164 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3166 void PR_Cmd_Init(void)
3168 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3172 void PR_Cmd_Reset(void)
3174 Mem_EmptyPool(pr_strings_mempool);
3175 PR_Files_CloseAll();