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, 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)
832 // cycle to the next one
836 if (check > svs.maxclients)
837 check = svs.maxclients;
839 if (check == svs.maxclients)
846 pr_xfunction->builtinsprofile++;
847 if (i == svs.maxclients+1)
853 break; // didn't find anything else
857 if (ent->v->health <= 0)
859 if ((int)ent->v->flags & FL_NOTARGET)
862 // anything that is a client, or has a client as an enemy
866 // get the PVS for the entity
867 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
868 memcpy (checkpvs, sv.worldmodel->LeafPVS(sv.worldmodel, sv.worldmodel->PointInLeaf(sv.worldmodel, org)), (sv.worldmodel->numleafs+7)>>3 );
877 Returns a client (or object that has a client enemy) that would be a
880 If there is more than one valid option, they are cycled each frame
882 If (self.origin + self.viewofs) is not in the PVS of the current target,
883 it is not returned at all.
888 int c_invis, c_notvis;
889 void PF_checkclient (void)
896 // find a new check if on a new frame
897 if (sv.time - sv.lastchecktime >= 0.1)
899 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
900 sv.lastchecktime = sv.time;
903 // return check if it might be visible
904 ent = EDICT_NUM(sv.lastcheck);
905 if (ent->e->free || ent->v->health <= 0)
907 RETURN_EDICT(sv.edicts);
911 // if current entity can't possibly see the check entity, return 0
912 self = PROG_TO_EDICT(pr_global_struct->self);
913 VectorAdd (self->v->origin, self->v->view_ofs, view);
914 leaf = sv.worldmodel->PointInLeaf(sv.worldmodel, view);
917 l = (leaf - sv.worldmodel->leafs) - 1;
918 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
921 RETURN_EDICT(sv.edicts);
926 // might be able to see it
931 //============================================================================
938 Sends text over to the client's execution buffer
940 stuffcmd (clientent, value)
943 void PF_stuffcmd (void)
949 entnum = G_EDICTNUM(OFS_PARM0);
950 if (entnum < 1 || entnum > svs.maxclients)
951 Host_Error ("Parm 0 not a client");
952 str = G_STRING(OFS_PARM1);
955 host_client = &svs.clients[entnum-1];
956 Host_ClientCommands ("%s", str);
964 Sends text over to the client's execution buffer
969 void PF_localcmd (void)
973 str = G_STRING(OFS_PARM0);
988 str = G_STRING(OFS_PARM0);
990 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
1000 void PF_cvar_set (void)
1004 var = G_STRING(OFS_PARM0);
1005 val = G_STRING(OFS_PARM1);
1007 Cvar_Set (var, val);
1014 Returns a chain of entities that have origins within a spherical area
1016 findradius (origin, radius)
1019 void PF_findradius (void)
1021 edict_t *ent, *chain;
1028 chain = (edict_t *)sv.edicts;
1030 org = G_VECTOR(OFS_PARM0);
1031 radius = G_FLOAT(OFS_PARM1);
1032 radius2 = radius * radius;
1034 ent = NEXT_EDICT(sv.edicts);
1035 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1037 pr_xfunction->builtinsprofile++;
1040 if (ent->v->solid == SOLID_NOT)
1043 // LordHavoc: compare against bounding box rather than center,
1044 // and use DotProduct instead of Length, major speedup
1045 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1046 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1047 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1048 if (DotProduct(eorg, eorg) > radius2)
1051 ent->v->chain = EDICT_TO_PROG(chain);
1055 RETURN_EDICT(chain);
1064 void PF_dprint (void)
1066 Con_DPrintf ("%s",PF_VarString(0));
1069 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1070 #define STRINGTEMP_BUFFERS 16
1071 #define STRINGTEMP_LENGTH 128
1072 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1073 static int pr_string_tempindex = 0;
1075 static char *PR_GetTempString(void)
1078 s = pr_string_temp[pr_string_tempindex];
1079 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1087 v = G_FLOAT(OFS_PARM0);
1089 s = PR_GetTempString();
1090 // LordHavoc: ftos improvement
1091 sprintf (s, "%g", v);
1092 G_INT(OFS_RETURN) = PR_SetString(s);
1098 v = G_FLOAT(OFS_PARM0);
1099 G_FLOAT(OFS_RETURN) = fabs(v);
1105 s = PR_GetTempString();
1106 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1107 G_INT(OFS_RETURN) = PR_SetString(s);
1113 s = PR_GetTempString();
1114 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1115 G_INT(OFS_RETURN) = PR_SetString(s);
1118 void PF_Spawn (void)
1121 pr_xfunction->builtinsprofile += 20;
1126 void PF_Remove (void)
1129 pr_xfunction->builtinsprofile += 20;
1131 ed = G_EDICT(OFS_PARM0);
1132 if (ed == sv.edicts)
1133 Host_Error("remove: tried to remove world\n");
1134 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1135 Host_Error("remove: tried to remove a client\n");
1140 // entity (entity start, .string field, string match) find = #5;
1148 e = G_EDICTNUM(OFS_PARM0);
1149 f = G_INT(OFS_PARM1);
1150 s = G_STRING(OFS_PARM2);
1153 RETURN_EDICT(sv.edicts);
1157 for (e++ ; e < sv.num_edicts ; e++)
1159 pr_xfunction->builtinsprofile++;
1173 RETURN_EDICT(sv.edicts);
1176 // LordHavoc: added this for searching float, int, and entity reference fields
1177 void PF_FindFloat (void)
1184 e = G_EDICTNUM(OFS_PARM0);
1185 f = G_INT(OFS_PARM1);
1186 s = G_FLOAT(OFS_PARM2);
1188 for (e++ ; e < sv.num_edicts ; e++)
1190 pr_xfunction->builtinsprofile++;
1194 if (E_FLOAT(ed,f) == s)
1201 RETURN_EDICT(sv.edicts);
1204 // chained search for strings in entity fields
1205 // entity(.string field, string match) findchain = #402;
1206 void PF_findchain (void)
1211 edict_t *ent, *chain;
1213 chain = (edict_t *)sv.edicts;
1215 f = G_INT(OFS_PARM0);
1216 s = G_STRING(OFS_PARM1);
1219 RETURN_EDICT(sv.edicts);
1223 ent = NEXT_EDICT(sv.edicts);
1224 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1226 pr_xfunction->builtinsprofile++;
1229 t = E_STRING(ent,f);
1235 ent->v->chain = EDICT_TO_PROG(chain);
1239 RETURN_EDICT(chain);
1242 // LordHavoc: chained search for float, int, and entity reference fields
1243 // entity(.string field, float match) findchainfloat = #403;
1244 void PF_findchainfloat (void)
1249 edict_t *ent, *chain;
1251 chain = (edict_t *)sv.edicts;
1253 f = G_INT(OFS_PARM0);
1254 s = G_FLOAT(OFS_PARM1);
1256 ent = NEXT_EDICT(sv.edicts);
1257 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1259 pr_xfunction->builtinsprofile++;
1262 if (E_FLOAT(ent,f) != s)
1265 ent->v->chain = EDICT_TO_PROG(chain);
1269 RETURN_EDICT(chain);
1272 void PR_CheckEmptyString (char *s)
1275 Host_Error ("Bad string");
1278 void PF_precache_file (void)
1279 { // precache_file is only used to copy files with qcc, it does nothing
1280 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1283 void PF_precache_sound (void)
1288 if (sv.state != ss_loading)
1289 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1291 s = G_STRING(OFS_PARM0);
1292 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1293 PR_CheckEmptyString (s);
1295 for (i=0 ; i<MAX_SOUNDS ; i++)
1297 if (!sv.sound_precache[i])
1299 sv.sound_precache[i] = s;
1302 if (!strcmp(sv.sound_precache[i], s))
1305 Host_Error ("PF_precache_sound: overflow");
1308 void PF_precache_model (void)
1313 if (sv.state != ss_loading)
1314 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1316 s = G_STRING(OFS_PARM0);
1317 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1319 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1320 PR_CheckEmptyString (s);
1322 for (i=0 ; i<MAX_MODELS ; i++)
1324 if (!sv.model_precache[i])
1326 sv.model_precache[i] = s;
1327 sv.models[i] = Mod_ForName (s, true, false, false);
1330 if (!strcmp(sv.model_precache[i], s))
1333 Host_Error ("PF_precache_model: overflow");
1337 void PF_coredump (void)
1342 void PF_traceon (void)
1347 void PF_traceoff (void)
1352 void PF_eprint (void)
1354 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1361 float(float yaw, float dist) walkmove
1364 void PF_walkmove (void)
1372 ent = PROG_TO_EDICT(pr_global_struct->self);
1373 yaw = G_FLOAT(OFS_PARM0);
1374 dist = G_FLOAT(OFS_PARM1);
1376 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1378 G_FLOAT(OFS_RETURN) = 0;
1382 yaw = yaw*M_PI*2 / 360;
1384 move[0] = cos(yaw)*dist;
1385 move[1] = sin(yaw)*dist;
1388 // save program state, because SV_movestep may call other progs
1389 oldf = pr_xfunction;
1390 oldself = pr_global_struct->self;
1392 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1395 // restore program state
1396 pr_xfunction = oldf;
1397 pr_global_struct->self = oldself;
1407 void PF_droptofloor (void)
1413 ent = PROG_TO_EDICT(pr_global_struct->self);
1415 VectorCopy (ent->v->origin, end);
1418 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1420 if (trace.fraction == 1)
1421 G_FLOAT(OFS_RETURN) = 0;
1424 VectorCopy (trace.endpos, ent->v->origin);
1425 SV_LinkEdict (ent, false);
1426 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1427 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1428 G_FLOAT(OFS_RETURN) = 1;
1429 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1430 ent->e->suspendedinairflag = true;
1438 void(float style, string value) lightstyle
1441 void PF_lightstyle (void)
1448 style = G_FLOAT(OFS_PARM0);
1449 val = G_STRING(OFS_PARM1);
1451 // change the string in sv
1452 sv.lightstyles[style] = val;
1454 // send message to all clients on this server
1455 if (sv.state != ss_active)
1458 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1459 if (client->active || client->spawned)
1461 MSG_WriteChar (&client->message, svc_lightstyle);
1462 MSG_WriteChar (&client->message,style);
1463 MSG_WriteString (&client->message, val);
1470 f = G_FLOAT(OFS_PARM0);
1472 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1474 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1476 void PF_floor (void)
1478 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1482 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1491 void PF_checkbottom (void)
1493 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1501 void PF_pointcontents (void)
1503 G_FLOAT(OFS_RETURN) = sv.worldmodel->PointContents(sv.worldmodel, G_VECTOR(OFS_PARM0));
1510 entity nextent(entity)
1513 void PF_nextent (void)
1518 i = G_EDICTNUM(OFS_PARM0);
1521 pr_xfunction->builtinsprofile++;
1523 if (i == sv.num_edicts)
1525 RETURN_EDICT(sv.edicts);
1541 Pick a vector for the player to shoot along
1542 vector aim(entity, missilespeed)
1547 edict_t *ent, *check, *bestent;
1548 vec3_t start, dir, end, bestdir;
1551 float dist, bestdist;
1554 ent = G_EDICT(OFS_PARM0);
1555 speed = G_FLOAT(OFS_PARM1);
1557 VectorCopy (ent->v->origin, start);
1560 // try sending a trace straight
1561 VectorCopy (pr_global_struct->v_forward, dir);
1562 VectorMA (start, 2048, dir, end);
1563 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1564 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1565 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1567 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1572 // try all possible entities
1573 VectorCopy (dir, bestdir);
1574 bestdist = sv_aim.value;
1577 check = NEXT_EDICT(sv.edicts);
1578 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1580 pr_xfunction->builtinsprofile++;
1581 if (check->v->takedamage != DAMAGE_AIM)
1585 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1586 continue; // don't aim at teammate
1587 for (j=0 ; j<3 ; j++)
1588 end[j] = check->v->origin[j]
1589 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1590 VectorSubtract (end, start, dir);
1591 VectorNormalize (dir);
1592 dist = DotProduct (dir, pr_global_struct->v_forward);
1593 if (dist < bestdist)
1594 continue; // to far to turn
1595 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1596 if (tr.ent == check)
1597 { // can shoot at this one
1605 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1606 dist = DotProduct (dir, pr_global_struct->v_forward);
1607 VectorScale (pr_global_struct->v_forward, dist, end);
1609 VectorNormalize (end);
1610 VectorCopy (end, G_VECTOR(OFS_RETURN));
1614 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1622 This was a major timewaster in progs, so it was converted to C
1625 void PF_changeyaw (void)
1628 float ideal, current, move, speed;
1630 ent = PROG_TO_EDICT(pr_global_struct->self);
1631 current = ANGLEMOD(ent->v->angles[1]);
1632 ideal = ent->v->ideal_yaw;
1633 speed = ent->v->yaw_speed;
1635 if (current == ideal)
1637 move = ideal - current;
1638 if (ideal > current)
1659 ent->v->angles[1] = ANGLEMOD (current + move);
1667 void PF_changepitch (void)
1670 float ideal, current, move, speed;
1673 ent = G_EDICT(OFS_PARM0);
1674 current = ANGLEMOD( ent->v->angles[0] );
1675 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1676 ideal = val->_float;
1679 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1682 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1683 speed = val->_float;
1686 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1690 if (current == ideal)
1692 move = ideal - current;
1693 if (ideal > current)
1714 ent->v->angles[0] = ANGLEMOD (current + move);
1718 ===============================================================================
1722 ===============================================================================
1725 #define MSG_BROADCAST 0 // unreliable to all
1726 #define MSG_ONE 1 // reliable to one (msg_entity)
1727 #define MSG_ALL 2 // reliable to all
1728 #define MSG_INIT 3 // write to the init string
1730 sizebuf_t *WriteDest (void)
1736 dest = G_FLOAT(OFS_PARM0);
1740 return &sv.datagram;
1743 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1744 entnum = NUM_FOR_EDICT(ent);
1745 if (entnum < 1 || entnum > svs.maxclients)
1746 Host_Error ("WriteDest: not a client");
1747 return &svs.clients[entnum-1].message;
1750 return &sv.reliable_datagram;
1756 Host_Error ("WriteDest: bad destination");
1763 void PF_WriteByte (void)
1765 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1768 void PF_WriteChar (void)
1770 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1773 void PF_WriteShort (void)
1775 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1778 void PF_WriteLong (void)
1780 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1783 void PF_WriteAngle (void)
1785 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1788 void PF_WriteCoord (void)
1790 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1793 void PF_WriteString (void)
1795 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1799 void PF_WriteEntity (void)
1801 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1804 //=============================================================================
1806 void PF_makestatic (void)
1811 ent = G_EDICT(OFS_PARM0);
1814 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1819 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1820 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1821 MSG_WriteShort (&sv.signon, ent->v->frame);
1825 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1826 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1827 MSG_WriteByte (&sv.signon, ent->v->frame);
1830 MSG_WriteByte (&sv.signon, ent->v->colormap);
1831 MSG_WriteByte (&sv.signon, ent->v->skin);
1832 for (i=0 ; i<3 ; i++)
1834 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1835 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1838 // throw the entity away now
1842 //=============================================================================
1849 void PF_setspawnparms (void)
1855 ent = G_EDICT(OFS_PARM0);
1856 i = NUM_FOR_EDICT(ent);
1857 if (i < 1 || i > svs.maxclients)
1858 Host_Error ("Entity is not a client");
1860 // copy spawn parms out of the client_t
1861 client = svs.clients + (i-1);
1863 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1864 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1872 void PF_changelevel (void)
1876 // make sure we don't issue two changelevels
1877 if (svs.changelevel_issued)
1879 svs.changelevel_issued = true;
1881 s = G_STRING(OFS_PARM0);
1882 Cbuf_AddText (va("changelevel %s\n",s));
1887 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1892 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1897 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1904 Returns a vector of length < 1
1909 void PF_randomvec (void)
1914 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1915 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1916 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1918 while (DotProduct(temp, temp) >= 1);
1919 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1922 void SV_LightPoint (vec3_t color, vec3_t p);
1927 Returns a color vector indicating the lighting at the requested point.
1929 (Internal Operation note: actually measures the light beneath the point, just like
1930 the model lighting on the client)
1935 void PF_GetLight (void)
1939 p = G_VECTOR(OFS_PARM0);
1940 SV_LightPoint (color, p);
1941 VectorCopy (color, G_VECTOR(OFS_RETURN));
1944 #define MAX_QC_CVARS 128
1945 cvar_t qc_cvar[MAX_QC_CVARS];
1948 void PF_registercvar (void)
1952 name = G_STRING(OFS_PARM0);
1953 value = G_STRING(OFS_PARM1);
1954 G_FLOAT(OFS_RETURN) = 0;
1955 // first check to see if it has already been defined
1956 if (Cvar_FindVar (name))
1959 // check for overlap with a command
1960 if (Cmd_Exists (name))
1962 Con_Printf ("PF_registercvar: %s is a command\n", name);
1966 if (currentqc_cvar >= MAX_QC_CVARS)
1967 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1969 // copy the name and value
1970 variable = &qc_cvar[currentqc_cvar++];
1971 variable->name = Z_Malloc (strlen(name)+1);
1972 strcpy (variable->name, name);
1973 variable->string = Z_Malloc (strlen(value)+1);
1974 strcpy (variable->string, value);
1975 variable->value = atof (value);
1977 Cvar_RegisterVariable(variable);
1978 G_FLOAT(OFS_RETURN) = 1; // success
1985 returns the minimum of two supplied floats
1992 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1994 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1995 else if (pr_argc >= 3)
1998 float f = G_FLOAT(OFS_PARM0);
1999 for (i = 1;i < pr_argc;i++)
2000 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2001 f = G_FLOAT((OFS_PARM0+i*3));
2002 G_FLOAT(OFS_RETURN) = f;
2005 Host_Error("min: must supply at least 2 floats\n");
2012 returns the maximum of two supplied floats
2019 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2021 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2022 else if (pr_argc >= 3)
2025 float f = G_FLOAT(OFS_PARM0);
2026 for (i = 1;i < pr_argc;i++)
2027 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2028 f = G_FLOAT((OFS_PARM0+i*3));
2029 G_FLOAT(OFS_RETURN) = f;
2032 Host_Error("max: must supply at least 2 floats\n");
2039 returns number bounded by supplied range
2041 min(min, value, max)
2044 void PF_bound (void)
2046 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2053 returns a raised to power b
2060 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2067 copies data from one entity to another
2069 copyentity(src, dst)
2072 void PF_copyentity (void)
2075 in = G_EDICT(OFS_PARM0);
2076 out = G_EDICT(OFS_PARM1);
2077 memcpy(out->v, in->v, progs->entityfields * 4);
2084 sets the color of a client and broadcasts the update to all connected clients
2086 setcolor(clientent, value)
2089 void PF_setcolor (void)
2095 entnum = G_EDICTNUM(OFS_PARM0);
2096 i = G_FLOAT(OFS_PARM1);
2098 if (entnum < 1 || entnum > svs.maxclients)
2100 Con_Printf ("tried to setcolor a non-client\n");
2104 client = &svs.clients[entnum-1];
2105 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2108 client->old_colors = i;
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();