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 "
131 "KRIMZON_SV_PARSECLIENTCOMMAND "
137 qboolean checkextension(char *name)
142 for (e = ENGINE_EXTENSIONS;*e;e++)
149 while (*e && *e != ' ')
151 if (e - start == len)
152 if (!strncasecmp(start, name, len))
162 returns true if the extension is supported by the server
164 checkextension(extensionname)
167 void PF_checkextension (void)
169 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
176 This is a TERMINAL error, which will kill off the entire server.
188 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
189 ed = PROG_TO_EDICT(pr_global_struct->self);
192 Host_Error ("Program error");
199 Dumps out self, then an error message. The program is aborted and self is
200 removed, but the level can continue.
205 void PF_objerror (void)
211 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
212 ed = PROG_TO_EDICT(pr_global_struct->self);
222 Writes new values for v_forward, v_up, and v_right based on angles
226 void PF_makevectors (void)
228 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
235 Writes new values for v_forward, v_up, and v_right based on the given forward vector
236 vectorvectors(vector, vector)
239 void PF_vectorvectors (void)
241 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
242 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
249 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.
251 setorigin (entity, origin)
254 void PF_setorigin (void)
259 e = G_EDICT(OFS_PARM0);
260 org = G_VECTOR(OFS_PARM1);
261 VectorCopy (org, e->v->origin);
262 SV_LinkEdict (e, false);
266 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
270 for (i=0 ; i<3 ; i++)
272 Host_Error ("backwards mins/maxs");
274 // set derived values
275 VectorCopy (min, e->v->mins);
276 VectorCopy (max, e->v->maxs);
277 VectorSubtract (max, min, e->v->size);
279 SV_LinkEdict (e, false);
286 the size box is rotated by the current angle
287 LordHavoc: no it isn't...
289 setsize (entity, minvector, maxvector)
292 void PF_setsize (void)
297 e = G_EDICT(OFS_PARM0);
298 min = G_VECTOR(OFS_PARM1);
299 max = G_VECTOR(OFS_PARM2);
300 SetMinMaxSize (e, min, max, false);
308 setmodel(entity, model)
311 void PF_setmodel (void)
318 e = G_EDICT(OFS_PARM0);
319 m = G_STRING(OFS_PARM1);
321 // check to see if model was properly precached
322 for (i=0, check = sv.model_precache ; *check ; i++, check++)
323 if (!strcmp(*check, m))
327 Host_Error ("no precache: %s\n", m);
330 e->v->model = PR_SetString(*check);
331 e->v->modelindex = i;
333 mod = sv.models[ (int)e->v->modelindex];
336 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
338 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
345 broadcast print to everyone on server
350 void PF_bprint (void)
355 SV_BroadcastPrintf ("%s", s);
362 single print to a specific client
364 sprint(clientent, value)
367 void PF_sprint (void)
373 entnum = G_EDICTNUM(OFS_PARM0);
376 if (entnum < 1 || entnum > svs.maxclients)
378 Con_Printf ("tried to sprint to a non-client\n");
382 client = &svs.clients[entnum-1];
384 MSG_WriteChar (&client->message,svc_print);
385 MSG_WriteString (&client->message, s );
393 single print to a specific client
395 centerprint(clientent, value)
398 void PF_centerprint (void)
404 entnum = G_EDICTNUM(OFS_PARM0);
407 if (entnum < 1 || entnum > svs.maxclients)
409 Con_Printf ("tried to sprint to a non-client\n");
413 client = &svs.clients[entnum-1];
415 MSG_WriteChar (&client->message,svc_centerprint);
416 MSG_WriteString (&client->message, s );
424 vector normalize(vector)
427 void PF_normalize (void)
433 value1 = G_VECTOR(OFS_PARM0);
435 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
439 newvalue[0] = newvalue[1] = newvalue[2] = 0;
443 newvalue[0] = value1[0] * new;
444 newvalue[1] = value1[1] * new;
445 newvalue[2] = value1[2] * new;
448 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
463 value1 = G_VECTOR(OFS_PARM0);
465 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
468 G_FLOAT(OFS_RETURN) = new;
475 float vectoyaw(vector)
478 void PF_vectoyaw (void)
483 value1 = G_VECTOR(OFS_PARM0);
485 if (value1[1] == 0 && value1[0] == 0)
489 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
494 G_FLOAT(OFS_RETURN) = yaw;
502 vector vectoangles(vector)
505 void PF_vectoangles (void)
511 value1 = G_VECTOR(OFS_PARM0);
513 if (value1[1] == 0 && value1[0] == 0)
523 // LordHavoc: optimized a bit
526 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
530 else if (value1[1] > 0)
535 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
536 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
541 G_FLOAT(OFS_RETURN+0) = pitch;
542 G_FLOAT(OFS_RETURN+1) = yaw;
543 G_FLOAT(OFS_RETURN+2) = 0;
550 Returns a number from 0<= num < 1
555 void PF_random (void)
559 num = (rand ()&0x7fff) / ((float)0x7fff);
561 G_FLOAT(OFS_RETURN) = num;
568 particle(origin, color, count)
571 void PF_particle (void)
577 org = G_VECTOR(OFS_PARM0);
578 dir = G_VECTOR(OFS_PARM1);
579 color = G_FLOAT(OFS_PARM2);
580 count = G_FLOAT(OFS_PARM3);
581 SV_StartParticle (org, dir, color, count);
591 void PF_ambientsound (void)
596 float vol, attenuation;
597 int i, soundnum, large;
599 pos = G_VECTOR (OFS_PARM0);
600 samp = G_STRING(OFS_PARM1);
601 vol = G_FLOAT(OFS_PARM2);
602 attenuation = G_FLOAT(OFS_PARM3);
604 // check to see if samp was properly precached
605 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
606 if (!strcmp(*check,samp))
611 Con_Printf ("no precache: %s\n", samp);
619 // add an svc_spawnambient command to the level signon packet
622 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
624 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
626 for (i=0 ; i<3 ; i++)
627 MSG_WriteDPCoord(&sv.signon, pos[i]);
630 MSG_WriteShort (&sv.signon, soundnum);
632 MSG_WriteByte (&sv.signon, soundnum);
634 MSG_WriteByte (&sv.signon, vol*255);
635 MSG_WriteByte (&sv.signon, attenuation*64);
643 Each entity can have eight independant sound sources, like voice,
646 Channel 0 is an auto-allocate channel, the others override anything
647 already running on that entity/channel pair.
649 An attenuation of 0 will play full volume everywhere in the level.
650 Larger attenuations will drop off.
662 entity = G_EDICT(OFS_PARM0);
663 channel = G_FLOAT(OFS_PARM1);
664 sample = G_STRING(OFS_PARM2);
665 volume = G_FLOAT(OFS_PARM3) * 255;
666 attenuation = G_FLOAT(OFS_PARM4);
668 if (volume < 0 || volume > 255)
669 Host_Error ("SV_StartSound: volume = %i", volume);
671 if (attenuation < 0 || attenuation > 4)
672 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
674 if (channel < 0 || channel > 7)
675 Host_Error ("SV_StartSound: channel = %i", channel);
677 SV_StartSound (entity, channel, sample, volume, attenuation);
689 Host_Error ("break statement");
696 Used for use tracing and shot targeting
697 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
698 if the tryents flag is set.
700 traceline (vector1, vector2, tryents)
703 void PF_traceline (void)
710 pr_xfunction->builtinsprofile += 30;
712 v1 = G_VECTOR(OFS_PARM0);
713 v2 = G_VECTOR(OFS_PARM1);
714 nomonsters = G_FLOAT(OFS_PARM2);
715 ent = G_EDICT(OFS_PARM3);
717 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
719 pr_global_struct->trace_allsolid = trace.allsolid;
720 pr_global_struct->trace_startsolid = trace.startsolid;
721 pr_global_struct->trace_fraction = trace.fraction;
722 pr_global_struct->trace_inwater = trace.inwater;
723 pr_global_struct->trace_inopen = trace.inopen;
724 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
725 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
726 pr_global_struct->trace_plane_dist = trace.plane.dist;
728 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
730 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
731 // FIXME: add trace_endcontents
739 Used for use tracing and shot targeting
740 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
741 if the tryents flag is set.
743 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
746 // LordHavoc: added this for my own use, VERY useful, similar to traceline
747 void PF_tracebox (void)
749 float *v1, *v2, *m1, *m2;
754 pr_xfunction->builtinsprofile += 30;
756 v1 = G_VECTOR(OFS_PARM0);
757 m1 = G_VECTOR(OFS_PARM1);
758 m2 = G_VECTOR(OFS_PARM2);
759 v2 = G_VECTOR(OFS_PARM3);
760 nomonsters = G_FLOAT(OFS_PARM4);
761 ent = G_EDICT(OFS_PARM5);
763 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
765 pr_global_struct->trace_allsolid = trace.allsolid;
766 pr_global_struct->trace_startsolid = trace.startsolid;
767 pr_global_struct->trace_fraction = trace.fraction;
768 pr_global_struct->trace_inwater = trace.inwater;
769 pr_global_struct->trace_inopen = trace.inopen;
770 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
771 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
772 pr_global_struct->trace_plane_dist = trace.plane.dist;
774 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
776 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
779 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
780 void PF_TraceToss (void)
786 pr_xfunction->builtinsprofile += 600;
788 ent = G_EDICT(OFS_PARM0);
789 ignore = G_EDICT(OFS_PARM1);
791 trace = SV_Trace_Toss (ent, ignore);
793 pr_global_struct->trace_allsolid = trace.allsolid;
794 pr_global_struct->trace_startsolid = trace.startsolid;
795 pr_global_struct->trace_fraction = trace.fraction;
796 pr_global_struct->trace_inwater = trace.inwater;
797 pr_global_struct->trace_inopen = trace.inopen;
798 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
799 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
800 pr_global_struct->trace_plane_dist = trace.plane.dist;
802 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
804 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
812 Returns true if the given entity can move to the given position from it's
813 current position by walking or rolling.
815 scalar checkpos (entity, vector)
818 void PF_checkpos (void)
822 //============================================================================
824 qbyte checkpvs[MAX_MAP_LEAFS/8];
826 int PF_newcheckclient (int check)
834 // cycle to the next one
838 if (check > svs.maxclients)
839 check = svs.maxclients;
841 if (check == svs.maxclients)
848 pr_xfunction->builtinsprofile++;
849 if (i == svs.maxclients+1)
855 break; // didn't find anything else
859 if (ent->v->health <= 0)
861 if ((int)ent->v->flags & FL_NOTARGET)
864 // anything that is a client, or has a client as an enemy
868 // get the PVS for the entity
869 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
870 leaf = Mod_PointInLeaf (org, sv.worldmodel);
871 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
872 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
881 Returns a client (or object that has a client enemy) that would be a
884 If there is more than one valid option, they are cycled each frame
886 If (self.origin + self.viewofs) is not in the PVS of the current target,
887 it is not returned at all.
892 int c_invis, c_notvis;
893 void PF_checkclient (void)
900 // find a new check if on a new frame
901 if (sv.time - sv.lastchecktime >= 0.1)
903 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
904 sv.lastchecktime = sv.time;
907 // return check if it might be visible
908 ent = EDICT_NUM(sv.lastcheck);
909 if (ent->e->free || ent->v->health <= 0)
911 RETURN_EDICT(sv.edicts);
915 // if current entity can't possibly see the check entity, return 0
916 self = PROG_TO_EDICT(pr_global_struct->self);
917 VectorAdd (self->v->origin, self->v->view_ofs, view);
918 leaf = Mod_PointInLeaf (view, sv.worldmodel);
921 l = (leaf - sv.worldmodel->leafs) - 1;
922 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
925 RETURN_EDICT(sv.edicts);
930 // might be able to see it
935 //============================================================================
942 Sends text over to the client's execution buffer
944 stuffcmd (clientent, value)
947 void PF_stuffcmd (void)
953 entnum = G_EDICTNUM(OFS_PARM0);
954 if (entnum < 1 || entnum > svs.maxclients)
955 Host_Error ("Parm 0 not a client");
956 str = G_STRING(OFS_PARM1);
959 host_client = &svs.clients[entnum-1];
960 Host_ClientCommands ("%s", str);
968 Sends text over to the client's execution buffer
973 void PF_localcmd (void)
977 str = G_STRING(OFS_PARM0);
992 str = G_STRING(OFS_PARM0);
994 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
1004 void PF_cvar_set (void)
1008 var = G_STRING(OFS_PARM0);
1009 val = G_STRING(OFS_PARM1);
1011 Cvar_Set (var, val);
1018 Returns a chain of entities that have origins within a spherical area
1020 findradius (origin, radius)
1023 void PF_findradius (void)
1025 edict_t *ent, *chain;
1032 chain = (edict_t *)sv.edicts;
1034 org = G_VECTOR(OFS_PARM0);
1035 radius = G_FLOAT(OFS_PARM1);
1036 radius2 = radius * radius;
1038 ent = NEXT_EDICT(sv.edicts);
1039 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1041 pr_xfunction->builtinsprofile++;
1044 if (ent->v->solid == SOLID_NOT)
1047 // LordHavoc: compare against bounding box rather than center,
1048 // and use DotProduct instead of Length, major speedup
1049 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1050 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1051 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1052 if (DotProduct(eorg, eorg) > radius2)
1055 ent->v->chain = EDICT_TO_PROG(chain);
1059 RETURN_EDICT(chain);
1068 void PF_dprint (void)
1070 Con_DPrintf ("%s",PF_VarString(0));
1073 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1074 #define STRINGTEMP_BUFFERS 16
1075 #define STRINGTEMP_LENGTH 128
1076 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1077 static int pr_string_tempindex = 0;
1079 static char *PR_GetTempString(void)
1082 s = pr_string_temp[pr_string_tempindex];
1083 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1091 v = G_FLOAT(OFS_PARM0);
1093 s = PR_GetTempString();
1094 // LordHavoc: ftos improvement
1095 sprintf (s, "%g", v);
1096 G_INT(OFS_RETURN) = PR_SetString(s);
1102 v = G_FLOAT(OFS_PARM0);
1103 G_FLOAT(OFS_RETURN) = fabs(v);
1109 s = PR_GetTempString();
1110 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1111 G_INT(OFS_RETURN) = PR_SetString(s);
1117 s = PR_GetTempString();
1118 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1119 G_INT(OFS_RETURN) = PR_SetString(s);
1122 void PF_Spawn (void)
1125 pr_xfunction->builtinsprofile += 20;
1130 void PF_Remove (void)
1133 pr_xfunction->builtinsprofile += 20;
1135 ed = G_EDICT(OFS_PARM0);
1136 if (ed == sv.edicts)
1137 Host_Error("remove: tried to remove world\n");
1138 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1139 Host_Error("remove: tried to remove a client\n");
1144 // entity (entity start, .string field, string match) find = #5;
1152 e = G_EDICTNUM(OFS_PARM0);
1153 f = G_INT(OFS_PARM1);
1154 s = G_STRING(OFS_PARM2);
1157 RETURN_EDICT(sv.edicts);
1161 for (e++ ; e < sv.num_edicts ; e++)
1163 pr_xfunction->builtinsprofile++;
1177 RETURN_EDICT(sv.edicts);
1180 // LordHavoc: added this for searching float, int, and entity reference fields
1181 void PF_FindFloat (void)
1188 e = G_EDICTNUM(OFS_PARM0);
1189 f = G_INT(OFS_PARM1);
1190 s = G_FLOAT(OFS_PARM2);
1192 for (e++ ; e < sv.num_edicts ; e++)
1194 pr_xfunction->builtinsprofile++;
1198 if (E_FLOAT(ed,f) == s)
1205 RETURN_EDICT(sv.edicts);
1208 // chained search for strings in entity fields
1209 // entity(.string field, string match) findchain = #402;
1210 void PF_findchain (void)
1215 edict_t *ent, *chain;
1217 chain = (edict_t *)sv.edicts;
1219 f = G_INT(OFS_PARM0);
1220 s = G_STRING(OFS_PARM1);
1223 RETURN_EDICT(sv.edicts);
1227 ent = NEXT_EDICT(sv.edicts);
1228 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1230 pr_xfunction->builtinsprofile++;
1233 t = E_STRING(ent,f);
1239 ent->v->chain = EDICT_TO_PROG(chain);
1243 RETURN_EDICT(chain);
1246 // LordHavoc: chained search for float, int, and entity reference fields
1247 // entity(.string field, float match) findchainfloat = #403;
1248 void PF_findchainfloat (void)
1253 edict_t *ent, *chain;
1255 chain = (edict_t *)sv.edicts;
1257 f = G_INT(OFS_PARM0);
1258 s = G_FLOAT(OFS_PARM1);
1260 ent = NEXT_EDICT(sv.edicts);
1261 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1263 pr_xfunction->builtinsprofile++;
1266 if (E_FLOAT(ent,f) != s)
1269 ent->v->chain = EDICT_TO_PROG(chain);
1273 RETURN_EDICT(chain);
1276 void PR_CheckEmptyString (char *s)
1279 Host_Error ("Bad string");
1282 void PF_precache_file (void)
1283 { // precache_file is only used to copy files with qcc, it does nothing
1284 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1287 void PF_precache_sound (void)
1292 if (sv.state != ss_loading)
1293 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1295 s = G_STRING(OFS_PARM0);
1296 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1297 PR_CheckEmptyString (s);
1299 for (i=0 ; i<MAX_SOUNDS ; i++)
1301 if (!sv.sound_precache[i])
1303 sv.sound_precache[i] = s;
1306 if (!strcmp(sv.sound_precache[i], s))
1309 Host_Error ("PF_precache_sound: overflow");
1312 void PF_precache_model (void)
1317 if (sv.state != ss_loading)
1318 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1320 s = G_STRING(OFS_PARM0);
1321 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1323 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1324 PR_CheckEmptyString (s);
1326 for (i=0 ; i<MAX_MODELS ; i++)
1328 if (!sv.model_precache[i])
1330 sv.model_precache[i] = s;
1331 sv.models[i] = Mod_ForName (s, true, false, false);
1334 if (!strcmp(sv.model_precache[i], s))
1337 Host_Error ("PF_precache_model: overflow");
1341 void PF_coredump (void)
1346 void PF_traceon (void)
1351 void PF_traceoff (void)
1356 void PF_eprint (void)
1358 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1365 float(float yaw, float dist) walkmove
1368 void PF_walkmove (void)
1376 ent = PROG_TO_EDICT(pr_global_struct->self);
1377 yaw = G_FLOAT(OFS_PARM0);
1378 dist = G_FLOAT(OFS_PARM1);
1380 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1382 G_FLOAT(OFS_RETURN) = 0;
1386 yaw = yaw*M_PI*2 / 360;
1388 move[0] = cos(yaw)*dist;
1389 move[1] = sin(yaw)*dist;
1392 // save program state, because SV_movestep may call other progs
1393 oldf = pr_xfunction;
1394 oldself = pr_global_struct->self;
1396 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1399 // restore program state
1400 pr_xfunction = oldf;
1401 pr_global_struct->self = oldself;
1411 void PF_droptofloor (void)
1417 ent = PROG_TO_EDICT(pr_global_struct->self);
1419 VectorCopy (ent->v->origin, end);
1422 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1424 if (trace.fraction == 1)
1425 G_FLOAT(OFS_RETURN) = 0;
1428 VectorCopy (trace.endpos, ent->v->origin);
1429 SV_LinkEdict (ent, false);
1430 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1431 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1432 G_FLOAT(OFS_RETURN) = 1;
1433 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1434 ent->e->suspendedinairflag = true;
1442 void(float style, string value) lightstyle
1445 void PF_lightstyle (void)
1452 style = G_FLOAT(OFS_PARM0);
1453 val = G_STRING(OFS_PARM1);
1455 // change the string in sv
1456 sv.lightstyles[style] = val;
1458 // send message to all clients on this server
1459 if (sv.state != ss_active)
1462 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1463 if (client->active || client->spawned)
1465 MSG_WriteChar (&client->message, svc_lightstyle);
1466 MSG_WriteChar (&client->message,style);
1467 MSG_WriteString (&client->message, val);
1474 f = G_FLOAT(OFS_PARM0);
1476 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1478 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1480 void PF_floor (void)
1482 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1486 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1495 void PF_checkbottom (void)
1497 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1505 void PF_pointcontents (void)
1507 G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1514 entity nextent(entity)
1517 void PF_nextent (void)
1522 i = G_EDICTNUM(OFS_PARM0);
1525 pr_xfunction->builtinsprofile++;
1527 if (i == sv.num_edicts)
1529 RETURN_EDICT(sv.edicts);
1545 Pick a vector for the player to shoot along
1546 vector aim(entity, missilespeed)
1551 edict_t *ent, *check, *bestent;
1552 vec3_t start, dir, end, bestdir;
1555 float dist, bestdist;
1558 ent = G_EDICT(OFS_PARM0);
1559 speed = G_FLOAT(OFS_PARM1);
1561 VectorCopy (ent->v->origin, start);
1564 // try sending a trace straight
1565 VectorCopy (pr_global_struct->v_forward, dir);
1566 VectorMA (start, 2048, dir, end);
1567 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1568 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1569 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1571 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1576 // try all possible entities
1577 VectorCopy (dir, bestdir);
1578 bestdist = sv_aim.value;
1581 check = NEXT_EDICT(sv.edicts);
1582 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1584 pr_xfunction->builtinsprofile++;
1585 if (check->v->takedamage != DAMAGE_AIM)
1589 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1590 continue; // don't aim at teammate
1591 for (j=0 ; j<3 ; j++)
1592 end[j] = check->v->origin[j]
1593 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1594 VectorSubtract (end, start, dir);
1595 VectorNormalize (dir);
1596 dist = DotProduct (dir, pr_global_struct->v_forward);
1597 if (dist < bestdist)
1598 continue; // to far to turn
1599 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1600 if (tr.ent == check)
1601 { // can shoot at this one
1609 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1610 dist = DotProduct (dir, pr_global_struct->v_forward);
1611 VectorScale (pr_global_struct->v_forward, dist, end);
1613 VectorNormalize (end);
1614 VectorCopy (end, G_VECTOR(OFS_RETURN));
1618 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1626 This was a major timewaster in progs, so it was converted to C
1629 void PF_changeyaw (void)
1632 float ideal, current, move, speed;
1634 ent = PROG_TO_EDICT(pr_global_struct->self);
1635 current = ANGLEMOD(ent->v->angles[1]);
1636 ideal = ent->v->ideal_yaw;
1637 speed = ent->v->yaw_speed;
1639 if (current == ideal)
1641 move = ideal - current;
1642 if (ideal > current)
1663 ent->v->angles[1] = ANGLEMOD (current + move);
1671 void PF_changepitch (void)
1674 float ideal, current, move, speed;
1677 ent = G_EDICT(OFS_PARM0);
1678 current = ANGLEMOD( ent->v->angles[0] );
1679 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1680 ideal = val->_float;
1683 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1686 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1687 speed = val->_float;
1690 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1694 if (current == ideal)
1696 move = ideal - current;
1697 if (ideal > current)
1718 ent->v->angles[0] = ANGLEMOD (current + move);
1722 ===============================================================================
1726 ===============================================================================
1729 #define MSG_BROADCAST 0 // unreliable to all
1730 #define MSG_ONE 1 // reliable to one (msg_entity)
1731 #define MSG_ALL 2 // reliable to all
1732 #define MSG_INIT 3 // write to the init string
1734 sizebuf_t *WriteDest (void)
1740 dest = G_FLOAT(OFS_PARM0);
1744 return &sv.datagram;
1747 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1748 entnum = NUM_FOR_EDICT(ent);
1749 if (entnum < 1 || entnum > svs.maxclients)
1750 Host_Error ("WriteDest: not a client");
1751 return &svs.clients[entnum-1].message;
1754 return &sv.reliable_datagram;
1760 Host_Error ("WriteDest: bad destination");
1767 void PF_WriteByte (void)
1769 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1772 void PF_WriteChar (void)
1774 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1777 void PF_WriteShort (void)
1779 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1782 void PF_WriteLong (void)
1784 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1787 void PF_WriteAngle (void)
1789 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1792 void PF_WriteCoord (void)
1794 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1797 void PF_WriteString (void)
1799 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1803 void PF_WriteEntity (void)
1805 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1808 //=============================================================================
1810 void PF_makestatic (void)
1815 ent = G_EDICT(OFS_PARM0);
1818 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1823 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1824 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1825 MSG_WriteShort (&sv.signon, ent->v->frame);
1829 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1830 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1831 MSG_WriteByte (&sv.signon, ent->v->frame);
1834 MSG_WriteByte (&sv.signon, ent->v->colormap);
1835 MSG_WriteByte (&sv.signon, ent->v->skin);
1836 for (i=0 ; i<3 ; i++)
1838 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1839 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1842 // throw the entity away now
1846 //=============================================================================
1853 void PF_setspawnparms (void)
1859 ent = G_EDICT(OFS_PARM0);
1860 i = NUM_FOR_EDICT(ent);
1861 if (i < 1 || i > svs.maxclients)
1862 Host_Error ("Entity is not a client");
1864 // copy spawn parms out of the client_t
1865 client = svs.clients + (i-1);
1867 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1868 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1876 void PF_changelevel (void)
1880 // make sure we don't issue two changelevels
1881 if (svs.changelevel_issued)
1883 svs.changelevel_issued = true;
1885 s = G_STRING(OFS_PARM0);
1886 Cbuf_AddText (va("changelevel %s\n",s));
1891 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1896 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1901 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1908 Returns a vector of length < 1
1913 void PF_randomvec (void)
1918 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1919 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1920 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1922 while (DotProduct(temp, temp) >= 1);
1923 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1926 void SV_LightPoint (vec3_t color, vec3_t p);
1931 Returns a color vector indicating the lighting at the requested point.
1933 (Internal Operation note: actually measures the light beneath the point, just like
1934 the model lighting on the client)
1939 void PF_GetLight (void)
1943 p = G_VECTOR(OFS_PARM0);
1944 SV_LightPoint (color, p);
1945 VectorCopy (color, G_VECTOR(OFS_RETURN));
1948 #define MAX_QC_CVARS 128
1949 cvar_t qc_cvar[MAX_QC_CVARS];
1952 void PF_registercvar (void)
1956 name = G_STRING(OFS_PARM0);
1957 value = G_STRING(OFS_PARM1);
1958 G_FLOAT(OFS_RETURN) = 0;
1959 // first check to see if it has already been defined
1960 if (Cvar_FindVar (name))
1963 // check for overlap with a command
1964 if (Cmd_Exists (name))
1966 Con_Printf ("PF_registercvar: %s is a command\n", name);
1970 if (currentqc_cvar >= MAX_QC_CVARS)
1971 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1973 // copy the name and value
1974 variable = &qc_cvar[currentqc_cvar++];
1975 variable->name = Z_Malloc (strlen(name)+1);
1976 strcpy (variable->name, name);
1977 variable->string = Z_Malloc (strlen(value)+1);
1978 strcpy (variable->string, value);
1979 variable->value = atof (value);
1981 Cvar_RegisterVariable(variable);
1982 G_FLOAT(OFS_RETURN) = 1; // success
1989 returns the minimum of two supplied floats
1996 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1998 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1999 else if (pr_argc >= 3)
2002 float f = G_FLOAT(OFS_PARM0);
2003 for (i = 1;i < pr_argc;i++)
2004 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2005 f = G_FLOAT((OFS_PARM0+i*3));
2006 G_FLOAT(OFS_RETURN) = f;
2009 Host_Error("min: must supply at least 2 floats\n");
2016 returns the maximum of two supplied floats
2023 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2025 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2026 else if (pr_argc >= 3)
2029 float f = G_FLOAT(OFS_PARM0);
2030 for (i = 1;i < pr_argc;i++)
2031 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2032 f = G_FLOAT((OFS_PARM0+i*3));
2033 G_FLOAT(OFS_RETURN) = f;
2036 Host_Error("max: must supply at least 2 floats\n");
2043 returns number bounded by supplied range
2045 min(min, value, max)
2048 void PF_bound (void)
2050 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2057 returns a raised to power b
2064 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2071 copies data from one entity to another
2073 copyentity(src, dst)
2076 void PF_copyentity (void)
2079 in = G_EDICT(OFS_PARM0);
2080 out = G_EDICT(OFS_PARM1);
2081 memcpy(out->v, in->v, progs->entityfields * 4);
2088 sets the color of a client and broadcasts the update to all connected clients
2090 setcolor(clientent, value)
2093 void PF_setcolor (void)
2098 entnum = G_EDICTNUM(OFS_PARM0);
2099 i = G_FLOAT(OFS_PARM1);
2101 if (entnum < 1 || entnum > svs.maxclients)
2103 Con_Printf ("tried to setcolor a non-client\n");
2107 client = &svs.clients[entnum-1];
2109 client->edict->v->team = (i & 15) + 1;
2111 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2112 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2113 MSG_WriteByte (&sv.reliable_datagram, i);
2120 effect(origin, modelname, startframe, framecount, framerate)
2123 void PF_effect (void)
2126 s = G_STRING(OFS_PARM1);
2128 Host_Error("effect: no model specified\n");
2130 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2133 void PF_te_blood (void)
2135 if (G_FLOAT(OFS_PARM2) < 1)
2137 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2138 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2140 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2141 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2142 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2144 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2145 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2146 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2148 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2151 void PF_te_bloodshower (void)
2153 if (G_FLOAT(OFS_PARM3) < 1)
2155 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2156 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2158 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2159 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2160 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2162 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2163 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2164 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2166 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2168 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2171 void PF_te_explosionrgb (void)
2173 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2174 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2176 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2180 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2181 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2182 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2185 void PF_te_particlecube (void)
2187 if (G_FLOAT(OFS_PARM3) < 1)
2189 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2190 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2192 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2193 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2194 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2196 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2197 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2198 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2200 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2201 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2202 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2204 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2206 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2207 // gravity true/false
2208 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2210 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2213 void PF_te_particlerain (void)
2215 if (G_FLOAT(OFS_PARM3) < 1)
2217 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2218 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2220 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2221 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2222 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2224 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2225 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2226 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2228 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2232 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2234 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2237 void PF_te_particlesnow (void)
2239 if (G_FLOAT(OFS_PARM3) < 1)
2241 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2242 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2244 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2245 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2246 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2248 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2249 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2250 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2252 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2253 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2254 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2256 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2258 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2261 void PF_te_spark (void)
2263 if (G_FLOAT(OFS_PARM2) < 1)
2265 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2266 MSG_WriteByte(&sv.datagram, TE_SPARK);
2268 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2269 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2270 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2272 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2273 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2274 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2276 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2279 void PF_te_gunshotquad (void)
2281 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2282 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2286 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2289 void PF_te_spikequad (void)
2291 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2292 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2294 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2295 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2296 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2299 void PF_te_superspikequad (void)
2301 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2302 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2306 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2309 void PF_te_explosionquad (void)
2311 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2312 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2314 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2315 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2316 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2319 void PF_te_smallflash (void)
2321 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2322 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2324 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2325 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2326 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2329 void PF_te_customflash (void)
2331 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2333 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2334 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2336 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2337 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2338 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2340 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2342 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2344 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2345 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2346 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2349 void PF_te_gunshot (void)
2351 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2352 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2354 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2355 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2356 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2359 void PF_te_spike (void)
2361 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2362 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2364 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2365 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2366 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2369 void PF_te_superspike (void)
2371 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2372 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2375 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2376 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2379 void PF_te_explosion (void)
2381 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2382 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2384 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2385 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2386 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2389 void PF_te_tarexplosion (void)
2391 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2394 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2395 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2396 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2399 void PF_te_wizspike (void)
2401 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2402 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2404 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2405 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2406 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2409 void PF_te_knightspike (void)
2411 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2412 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2414 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2415 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2416 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2419 void PF_te_lavasplash (void)
2421 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2424 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2425 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2426 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2429 void PF_te_teleport (void)
2431 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2432 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2434 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2435 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2436 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2439 void PF_te_explosion2 (void)
2441 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2442 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2445 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2446 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2448 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2451 void PF_te_lightning1 (void)
2453 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2454 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2456 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2458 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2467 void PF_te_lightning2 (void)
2469 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2470 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2472 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2474 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2478 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2479 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2483 void PF_te_lightning3 (void)
2485 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2486 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2488 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2490 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2499 void PF_te_beam (void)
2501 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2502 MSG_WriteByte(&sv.datagram, TE_BEAM);
2504 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2508 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2510 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2511 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2512 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2515 void PF_te_plasmaburn (void)
2517 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2518 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2519 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2520 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2521 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2524 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2527 vec3_t v1, clipplanenormal, normal;
2528 vec_t clipplanedist, clipdist;
2530 if (surf->flags & SURF_PLANEBACK)
2531 VectorNegate(surf->plane->normal, normal);
2533 VectorCopy(surf->plane->normal, normal);
2534 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2536 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2537 VectorNormalizeFast(v1);
2538 CrossProduct(v1, normal, clipplanenormal);
2539 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2540 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2543 clipdist = -clipdist;
2544 VectorMA(out, clipdist, clipplanenormal, out);
2549 static msurface_t *getsurface(edict_t *ed, int surfnum)
2553 if (!ed || ed->e->free)
2555 modelindex = ed->v->modelindex;
2556 if (modelindex < 1 || modelindex >= MAX_MODELS)
2558 model = sv.models[modelindex];
2559 if (model->type != mod_brush)
2561 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2563 return model->surfaces + surfnum + model->firstmodelsurface;
2567 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2568 void PF_getsurfacenumpoints(void)
2571 // return 0 if no such surface
2572 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2574 G_FLOAT(OFS_RETURN) = 0;
2578 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2580 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2581 void PF_getsurfacepoint(void)
2586 VectorClear(G_VECTOR(OFS_RETURN));
2587 ed = G_EDICT(OFS_PARM0);
2588 if (!ed || ed->e->free)
2590 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2592 pointnum = G_FLOAT(OFS_PARM2);
2593 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2595 // FIXME: implement rotation/scaling
2596 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2598 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2599 void PF_getsurfacenormal(void)
2602 VectorClear(G_VECTOR(OFS_RETURN));
2603 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2605 // FIXME: implement rotation/scaling
2606 if (surf->flags & SURF_PLANEBACK)
2607 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2609 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2611 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2612 void PF_getsurfacetexture(void)
2615 G_INT(OFS_RETURN) = 0;
2616 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2618 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2620 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2621 void PF_getsurfacenearpoint(void)
2623 int surfnum, best, modelindex;
2625 vec_t dist, bestdist;
2630 G_FLOAT(OFS_RETURN) = -1;
2631 ed = G_EDICT(OFS_PARM0);
2632 point = G_VECTOR(OFS_PARM1);
2634 if (!ed || ed->e->free)
2636 modelindex = ed->v->modelindex;
2637 if (modelindex < 1 || modelindex >= MAX_MODELS)
2639 model = sv.models[modelindex];
2640 if (model->type != mod_brush)
2643 // FIXME: implement rotation/scaling
2644 VectorSubtract(point, ed->v->origin, p);
2646 bestdist = 1000000000;
2647 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2649 surf = model->surfaces + surfnum + model->firstmodelsurface;
2650 dist = PlaneDiff(p, surf->plane);
2652 if (dist < bestdist)
2654 clippointtosurface(surf, p, clipped);
2655 VectorSubtract(clipped, p, clipped);
2656 dist += DotProduct(clipped, clipped);
2657 if (dist < bestdist)
2664 G_FLOAT(OFS_RETURN) = best;
2666 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2667 void PF_getsurfaceclippedpoint(void)
2672 VectorClear(G_VECTOR(OFS_RETURN));
2673 ed = G_EDICT(OFS_PARM0);
2674 if (!ed || ed->e->free)
2676 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2678 // FIXME: implement rotation/scaling
2679 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2680 clippointtosurface(surf, p, out);
2681 // FIXME: implement rotation/scaling
2682 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2685 #define MAX_PRFILES 256
2687 qfile_t *pr_files[MAX_PRFILES];
2689 void PR_Files_Init(void)
2691 memset(pr_files, 0, sizeof(pr_files));
2694 void PR_Files_CloseAll(void)
2697 for (i = 0;i < MAX_PRFILES;i++)
2700 FS_Close(pr_files[i]);
2705 //float(string s) stof = #81; // get numerical value from a string
2708 char *s = PF_VarString(0);
2709 G_FLOAT(OFS_RETURN) = atof(s);
2712 //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
2716 char *modestring, *filename;
2717 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2718 if (pr_files[filenum] == NULL)
2720 if (filenum >= MAX_PRFILES)
2722 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2723 G_FLOAT(OFS_RETURN) = -2;
2726 mode = G_FLOAT(OFS_PARM1);
2729 case 0: // FILE_READ
2732 case 1: // FILE_APPEND
2735 case 2: // FILE_WRITE
2739 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2740 G_FLOAT(OFS_RETURN) = -3;
2743 filename = G_STRING(OFS_PARM0);
2744 // .. is parent directory on many platforms
2745 // / is parent directory on Amiga
2746 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2747 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2748 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2750 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2751 G_FLOAT(OFS_RETURN) = -4;
2754 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2755 if (pr_files[filenum] == NULL)
2756 G_FLOAT(OFS_RETURN) = -1;
2758 G_FLOAT(OFS_RETURN) = filenum;
2761 //void(float fhandle) fclose = #111; // closes a file
2762 void PF_fclose(void)
2764 int filenum = G_FLOAT(OFS_PARM0);
2765 if (filenum < 0 || filenum >= MAX_PRFILES)
2767 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2770 if (pr_files[filenum] == NULL)
2772 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2775 FS_Close(pr_files[filenum]);
2776 pr_files[filenum] = NULL;
2779 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2783 static char string[MAX_VARSTRING];
2784 int filenum = G_FLOAT(OFS_PARM0);
2785 if (filenum < 0 || filenum >= MAX_PRFILES)
2787 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2790 if (pr_files[filenum] == NULL)
2792 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2798 c = FS_Getc(pr_files[filenum]);
2799 if (c == '\r' || c == '\n' || c < 0)
2801 if (end < MAX_VARSTRING - 1)
2805 // remove \n following \r
2807 c = FS_Getc(pr_files[filenum]);
2808 if (developer.integer)
2809 Con_Printf("fgets: %s\n", string);
2811 G_INT(OFS_RETURN) = PR_SetString(string);
2813 G_INT(OFS_RETURN) = 0;
2816 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2820 char *s = PF_VarString(1);
2821 int filenum = G_FLOAT(OFS_PARM0);
2822 if (filenum < 0 || filenum >= MAX_PRFILES)
2824 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2827 if (pr_files[filenum] == NULL)
2829 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2832 if ((stringlength = strlen(s)))
2833 FS_Write(pr_files[filenum], s, stringlength);
2834 if (developer.integer)
2835 Con_Printf("fputs: %s\n", s);
2838 //float(string s) strlen = #114; // returns how many characters are in a string
2839 void PF_strlen(void)
2842 s = G_STRING(OFS_PARM0);
2844 G_FLOAT(OFS_RETURN) = strlen(s);
2846 G_FLOAT(OFS_RETURN) = 0;
2849 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2850 void PF_strcat(void)
2852 char *s = PF_VarString(0);
2853 G_INT(OFS_RETURN) = PR_SetString(s);
2856 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2857 void PF_substring(void)
2860 char *s, string[MAX_VARSTRING];
2861 s = G_STRING(OFS_PARM0);
2862 start = G_FLOAT(OFS_PARM1);
2863 end = G_FLOAT(OFS_PARM2) + start;
2866 for (i = 0;i < start && *s;i++, s++);
2867 for (i = 0;i < MAX_VARSTRING - 1 && *s && i < end;i++, s++)
2870 G_INT(OFS_RETURN) = PR_SetString(string);
2873 //vector(string s) stov = #117; // returns vector value from a string
2876 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2879 //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)
2880 void PF_strzone(void)
2883 in = G_STRING(OFS_PARM0);
2884 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2886 G_INT(OFS_RETURN) = PR_SetString(out);
2889 //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!!!)
2890 void PF_strunzone(void)
2892 Mem_Free(G_STRING(OFS_PARM0));
2895 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2896 //this function originally written by KrimZon, made shorter by LordHavoc
2897 void PF_clientcommand (void)
2899 client_t *temp_client;
2902 //find client for this entity
2903 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2904 if (i < 0 || i >= svs.maxclients)
2905 Host_Error("PF_clientcommand: entity is not a client");
2907 temp_client = host_client;
2908 host_client = &svs.clients[i];
2909 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2910 host_client = temp_client;
2913 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2914 //this function originally written by KrimZon, made shorter by LordHavoc
2915 char **tokens = NULL;
2916 int max_tokens, num_tokens = 0;
2917 void PF_tokenize (void)
2921 str = G_STRING(OFS_PARM0);
2926 for (i=0;i<num_tokens;i++)
2932 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2933 max_tokens = strlen(str);
2935 for (p = str;COM_ParseToken(&p) && num_tokens < max_tokens;num_tokens++)
2937 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2938 strcpy(tokens[num_tokens], com_token);
2941 G_FLOAT(OFS_RETURN) = num_tokens;
2944 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2945 //this function originally written by KrimZon, made shorter by LordHavoc
2948 int token_num = G_FLOAT(OFS_PARM0);
2949 if (token_num >= 0 && token_num < num_tokens)
2950 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2952 G_INT(OFS_RETURN) = PR_SetString("");
2956 builtin_t pr_builtin[] =
2959 PF_makevectors, // #1 void(entity e) makevectors
2960 PF_setorigin, // #2 void(entity e, vector o) setorigin
2961 PF_setmodel, // #3 void(entity e, string m) setmodel
2962 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2963 NULL, // #5 void(entity e, vector min, vector max) setabssize
2964 PF_break, // #6 void() break
2965 PF_random, // #7 float() random
2966 PF_sound, // #8 void(entity e, float chan, string samp) sound
2967 PF_normalize, // #9 vector(vector v) normalize
2968 PF_error, // #10 void(string e) error
2969 PF_objerror, // #11 void(string e) objerror
2970 PF_vlen, // #12 float(vector v) vlen
2971 PF_vectoyaw, // #13 float(vector v) vectoyaw
2972 PF_Spawn, // #14 entity() spawn
2973 PF_Remove, // #15 void(entity e) remove
2974 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2975 PF_checkclient, // #17 entity() clientlist
2976 PF_Find, // #18 entity(entity start, .string fld, string match) find
2977 PF_precache_sound, // #19 void(string s) precache_sound
2978 PF_precache_model, // #20 void(string s) precache_model
2979 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2980 PF_findradius, // #22 entity(vector org, float rad) findradius
2981 PF_bprint, // #23 void(string s) bprint
2982 PF_sprint, // #24 void(entity client, string s) sprint
2983 PF_dprint, // #25 void(string s) dprint
2984 PF_ftos, // #26 void(string s) ftos
2985 PF_vtos, // #27 void(string s) vtos
2986 PF_coredump, // #28 void() coredump
2987 PF_traceon, // #29 void() traceon
2988 PF_traceoff, // #30 void() traceoff
2989 PF_eprint, // #31 void(entity e) eprint
2990 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2992 PF_droptofloor, // #34 float() droptofloor
2993 PF_lightstyle, // #35 void(float style, string value) lightstyle
2994 PF_rint, // #36 float(float v) rint
2995 PF_floor, // #37 float(float v) floor
2996 PF_ceil, // #38 float(float v) ceil
2998 PF_checkbottom, // #40 float(entity e) checkbottom
2999 PF_pointcontents , // #41 float(vector v) pointcontents
3001 PF_fabs, // #43 float(float f) fabs
3002 PF_aim, // #44 vector(entity e, float speed) aim
3003 PF_cvar, // #45 float(string s) cvar
3004 PF_localcmd, // #46 void(string s) localcmd
3005 PF_nextent, // #47 entity(entity e) nextent
3006 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3007 PF_changeyaw, // #49 void() ChangeYaw
3009 PF_vectoangles, // #51 vector(vector v) vectoangles
3010 PF_WriteByte, // #52 void(float to, float f) WriteByte
3011 PF_WriteChar, // #53 void(float to, float f) WriteChar
3012 PF_WriteShort, // #54 void(float to, float f) WriteShort
3013 PF_WriteLong, // #55 void(float to, float f) WriteLong
3014 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3015 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3016 PF_WriteString, // #58 void(float to, string s) WriteString
3017 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3018 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3019 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3020 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3021 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3022 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3023 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3025 SV_MoveToGoal, // #67 void(float step) movetogoal
3026 PF_precache_file, // #68 string(string s) precache_file
3027 PF_makestatic, // #69 void(entity e) makestatic
3028 PF_changelevel, // #70 void(string s) changelevel
3030 PF_cvar_set, // #72 void(string var, string val) cvar_set
3031 PF_centerprint, // #73 void(entity client, strings) centerprint
3032 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3033 PF_precache_model, // #75 string(string s) precache_model2
3034 PF_precache_sound, // #76 string(string s) precache_sound2
3035 PF_precache_file, // #77 string(string s) precache_file2
3036 PF_setspawnparms, // #78 void(entity e) setspawnparms
3039 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3048 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3049 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3050 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3051 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3052 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3053 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3054 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3055 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3056 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3057 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3068 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3069 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3070 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3071 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3072 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3073 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3074 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3075 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3076 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3077 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3078 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3079 a a a a a a a a // #120-199
3080 a a a a a a a a a a // #200-299
3081 a a a a a a a a a a // #300-399
3082 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3083 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3084 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3085 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3086 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3087 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3088 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3089 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3090 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3091 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3092 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3093 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3094 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3095 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3096 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3097 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3098 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3099 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3100 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3101 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3102 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3103 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3104 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3105 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3106 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3107 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3108 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3109 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3110 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3111 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3112 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3113 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3114 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3115 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3116 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3117 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3118 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3119 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3120 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3121 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3122 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3123 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3124 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3132 a a a a a // #450-499 (LordHavoc)
3135 builtin_t *pr_builtins = pr_builtin;
3136 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3138 void PR_Cmd_Init(void)
3140 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3144 void PR_Cmd_Reset(void)
3146 Mem_EmptyPool(pr_strings_mempool);
3147 PR_Files_CloseAll();