2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
26 mempool_t *pr_strings_mempool;
28 #define MAX_VARSTRING 4096
30 char pr_varstring_temp[MAX_VARSTRING];
32 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
36 ===============================================================================
40 ===============================================================================
44 char *PF_VarString (int first)
50 out = pr_varstring_temp;
51 outend = pr_varstring_temp + sizeof(pr_varstring_temp) - 1;
52 for (i = first;i < pr_argc && out < outend;i++)
54 s = G_STRING((OFS_PARM0+i*3));
55 while (out < outend && *s)
59 return pr_varstring_temp;
62 char *ENGINE_EXTENSIONS =
72 "DP_ENT_CUSTOMCOLORMAP "
73 "DP_ENT_EXTERIORMODELTOCLIENT "
74 "DP_ENT_LOWPRECISION "
83 "DP_MOVETYPEBOUNCEMISSILE "
89 "DP_QC_FINDCHAINFLOAT "
95 "DP_QC_SINCOSSQRTPOW "
98 "DP_QC_VECTORVECTORS "
104 "DP_SV_DRAWONLYTOCLIENT "
106 "DP_SV_EXTERIORMODELTOCLIENT "
107 "DP_SV_NODRAWTOCLIENT "
108 "DP_SV_PLAYERPHYSICS "
114 "DP_TE_EXPLOSIONRGB "
116 "DP_TE_PARTICLECUBE "
117 "DP_TE_PARTICLERAIN "
118 "DP_TE_PARTICLESNOW "
120 "DP_TE_QUADEFFECTS1 "
123 "DP_TE_STANDARDEFFECTBUILTINS "
126 "KRIMZON_SV_PARSECLIENTCOMMAND "
132 qboolean checkextension(char *name)
137 for (e = ENGINE_EXTENSIONS;*e;e++)
144 while (*e && *e != ' ')
146 if (e - start == len)
147 if (!strncasecmp(start, name, len))
157 returns true if the extension is supported by the server
159 checkextension(extensionname)
162 void PF_checkextension (void)
164 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
171 This is a TERMINAL error, which will kill off the entire server.
183 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
184 ed = PROG_TO_EDICT(pr_global_struct->self);
187 Host_Error ("Program error");
194 Dumps out self, then an error message. The program is aborted and self is
195 removed, but the level can continue.
200 void PF_objerror (void)
206 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
207 ed = PROG_TO_EDICT(pr_global_struct->self);
217 Writes new values for v_forward, v_up, and v_right based on angles
221 void PF_makevectors (void)
223 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
230 Writes new values for v_forward, v_up, and v_right based on the given forward vector
231 vectorvectors(vector, vector)
234 void PF_vectorvectors (void)
236 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
237 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
244 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.
246 setorigin (entity, origin)
249 void PF_setorigin (void)
254 e = G_EDICT(OFS_PARM0);
255 org = G_VECTOR(OFS_PARM1);
256 VectorCopy (org, e->v->origin);
257 SV_LinkEdict (e, false);
261 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
265 for (i=0 ; i<3 ; i++)
267 Host_Error ("backwards mins/maxs");
269 // set derived values
270 VectorCopy (min, e->v->mins);
271 VectorCopy (max, e->v->maxs);
272 VectorSubtract (max, min, e->v->size);
274 SV_LinkEdict (e, false);
281 the size box is rotated by the current angle
282 LordHavoc: no it isn't...
284 setsize (entity, minvector, maxvector)
287 void PF_setsize (void)
292 e = G_EDICT(OFS_PARM0);
293 min = G_VECTOR(OFS_PARM1);
294 max = G_VECTOR(OFS_PARM2);
295 SetMinMaxSize (e, min, max, false);
303 setmodel(entity, model)
306 void PF_setmodel (void)
313 e = G_EDICT(OFS_PARM0);
314 m = G_STRING(OFS_PARM1);
316 // check to see if model was properly precached
317 for (i=0, check = sv.model_precache ; *check ; i++, check++)
318 if (!strcmp(*check, m))
322 Host_Error ("no precache: %s\n", m);
325 e->v->model = PR_SetString(*check);
326 e->v->modelindex = i;
328 mod = sv.models[ (int)e->v->modelindex];
331 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
333 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
340 broadcast print to everyone on server
345 void PF_bprint (void)
350 SV_BroadcastPrintf ("%s", s);
357 single print to a specific client
359 sprint(clientent, value)
362 void PF_sprint (void)
368 entnum = G_EDICTNUM(OFS_PARM0);
371 if (entnum < 1 || entnum > svs.maxclients)
373 Con_Printf ("tried to sprint to a non-client\n");
377 client = &svs.clients[entnum-1];
379 MSG_WriteChar (&client->message,svc_print);
380 MSG_WriteString (&client->message, s );
388 single print to a specific client
390 centerprint(clientent, value)
393 void PF_centerprint (void)
399 entnum = G_EDICTNUM(OFS_PARM0);
402 if (entnum < 1 || entnum > svs.maxclients)
404 Con_Printf ("tried to sprint to a non-client\n");
408 client = &svs.clients[entnum-1];
410 MSG_WriteChar (&client->message,svc_centerprint);
411 MSG_WriteString (&client->message, s );
419 vector normalize(vector)
422 void PF_normalize (void)
428 value1 = G_VECTOR(OFS_PARM0);
430 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
434 newvalue[0] = newvalue[1] = newvalue[2] = 0;
438 newvalue[0] = value1[0] * new;
439 newvalue[1] = value1[1] * new;
440 newvalue[2] = value1[2] * new;
443 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
458 value1 = G_VECTOR(OFS_PARM0);
460 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
463 G_FLOAT(OFS_RETURN) = new;
470 float vectoyaw(vector)
473 void PF_vectoyaw (void)
478 value1 = G_VECTOR(OFS_PARM0);
480 if (value1[1] == 0 && value1[0] == 0)
484 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
489 G_FLOAT(OFS_RETURN) = yaw;
497 vector vectoangles(vector)
500 void PF_vectoangles (void)
506 value1 = G_VECTOR(OFS_PARM0);
508 if (value1[1] == 0 && value1[0] == 0)
518 // LordHavoc: optimized a bit
521 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
525 else if (value1[1] > 0)
530 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
531 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
536 G_FLOAT(OFS_RETURN+0) = pitch;
537 G_FLOAT(OFS_RETURN+1) = yaw;
538 G_FLOAT(OFS_RETURN+2) = 0;
545 Returns a number from 0<= num < 1
550 void PF_random (void)
554 num = (rand ()&0x7fff) / ((float)0x7fff);
556 G_FLOAT(OFS_RETURN) = num;
563 particle(origin, color, count)
566 void PF_particle (void)
572 org = G_VECTOR(OFS_PARM0);
573 dir = G_VECTOR(OFS_PARM1);
574 color = G_FLOAT(OFS_PARM2);
575 count = G_FLOAT(OFS_PARM3);
576 SV_StartParticle (org, dir, color, count);
586 void PF_ambientsound (void)
591 float vol, attenuation;
592 int i, soundnum, large;
594 pos = G_VECTOR (OFS_PARM0);
595 samp = G_STRING(OFS_PARM1);
596 vol = G_FLOAT(OFS_PARM2);
597 attenuation = G_FLOAT(OFS_PARM3);
599 // check to see if samp was properly precached
600 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
601 if (!strcmp(*check,samp))
606 Con_Printf ("no precache: %s\n", samp);
614 // add an svc_spawnambient command to the level signon packet
617 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
619 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
621 for (i=0 ; i<3 ; i++)
622 MSG_WriteDPCoord(&sv.signon, pos[i]);
625 MSG_WriteShort (&sv.signon, soundnum);
627 MSG_WriteByte (&sv.signon, soundnum);
629 MSG_WriteByte (&sv.signon, vol*255);
630 MSG_WriteByte (&sv.signon, attenuation*64);
638 Each entity can have eight independant sound sources, like voice,
641 Channel 0 is an auto-allocate channel, the others override anything
642 already running on that entity/channel pair.
644 An attenuation of 0 will play full volume everywhere in the level.
645 Larger attenuations will drop off.
657 entity = G_EDICT(OFS_PARM0);
658 channel = G_FLOAT(OFS_PARM1);
659 sample = G_STRING(OFS_PARM2);
660 volume = G_FLOAT(OFS_PARM3) * 255;
661 attenuation = G_FLOAT(OFS_PARM4);
663 if (volume < 0 || volume > 255)
664 Host_Error ("SV_StartSound: volume = %i", volume);
666 if (attenuation < 0 || attenuation > 4)
667 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
669 if (channel < 0 || channel > 7)
670 Host_Error ("SV_StartSound: channel = %i", channel);
672 SV_StartSound (entity, channel, sample, volume, attenuation);
684 Host_Error ("break statement");
691 Used for use tracing and shot targeting
692 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
693 if the tryents flag is set.
695 traceline (vector1, vector2, tryents)
698 void PF_traceline (void)
705 pr_xfunction->builtinsprofile += 30;
707 v1 = G_VECTOR(OFS_PARM0);
708 v2 = G_VECTOR(OFS_PARM1);
709 nomonsters = G_FLOAT(OFS_PARM2);
710 ent = G_EDICT(OFS_PARM3);
712 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
714 pr_global_struct->trace_allsolid = trace.allsolid;
715 pr_global_struct->trace_startsolid = trace.startsolid;
716 pr_global_struct->trace_fraction = trace.fraction;
717 pr_global_struct->trace_inwater = trace.inwater;
718 pr_global_struct->trace_inopen = trace.inopen;
719 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
720 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
721 pr_global_struct->trace_plane_dist = trace.plane.dist;
723 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
725 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
726 // FIXME: add trace_endcontents
734 Used for use tracing and shot targeting
735 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
736 if the tryents flag is set.
738 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
741 // LordHavoc: added this for my own use, VERY useful, similar to traceline
742 void PF_tracebox (void)
744 float *v1, *v2, *m1, *m2;
749 pr_xfunction->builtinsprofile += 30;
751 v1 = G_VECTOR(OFS_PARM0);
752 m1 = G_VECTOR(OFS_PARM1);
753 m2 = G_VECTOR(OFS_PARM2);
754 v2 = G_VECTOR(OFS_PARM3);
755 nomonsters = G_FLOAT(OFS_PARM4);
756 ent = G_EDICT(OFS_PARM5);
758 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
760 pr_global_struct->trace_allsolid = trace.allsolid;
761 pr_global_struct->trace_startsolid = trace.startsolid;
762 pr_global_struct->trace_fraction = trace.fraction;
763 pr_global_struct->trace_inwater = trace.inwater;
764 pr_global_struct->trace_inopen = trace.inopen;
765 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
766 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
767 pr_global_struct->trace_plane_dist = trace.plane.dist;
769 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
771 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
774 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
775 void PF_TraceToss (void)
781 pr_xfunction->builtinsprofile += 600;
783 ent = G_EDICT(OFS_PARM0);
784 ignore = G_EDICT(OFS_PARM1);
786 trace = SV_Trace_Toss (ent, ignore);
788 pr_global_struct->trace_allsolid = trace.allsolid;
789 pr_global_struct->trace_startsolid = trace.startsolid;
790 pr_global_struct->trace_fraction = trace.fraction;
791 pr_global_struct->trace_inwater = trace.inwater;
792 pr_global_struct->trace_inopen = trace.inopen;
793 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
794 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
795 pr_global_struct->trace_plane_dist = trace.plane.dist;
797 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
799 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
807 Returns true if the given entity can move to the given position from it's
808 current position by walking or rolling.
810 scalar checkpos (entity, vector)
813 void PF_checkpos (void)
817 //============================================================================
819 qbyte checkpvs[MAX_MAP_LEAFS/8];
821 int PF_newcheckclient (int check)
827 // cycle to the next one
831 if (check > svs.maxclients)
832 check = svs.maxclients;
834 if (check == svs.maxclients)
841 pr_xfunction->builtinsprofile++;
842 if (i == svs.maxclients+1)
848 break; // didn't find anything else
852 if (ent->v->health <= 0)
854 if ((int)ent->v->flags & FL_NOTARGET)
857 // anything that is a client, or has a client as an enemy
861 // get the PVS for the entity
862 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
863 memcpy (checkpvs, sv.worldmodel->LeafPVS(sv.worldmodel, sv.worldmodel->PointInLeaf(sv.worldmodel, org)), (sv.worldmodel->numleafs+7)>>3 );
872 Returns a client (or object that has a client enemy) that would be a
875 If there is more than one valid option, they are cycled each frame
877 If (self.origin + self.viewofs) is not in the PVS of the current target,
878 it is not returned at all.
883 int c_invis, c_notvis;
884 void PF_checkclient (void)
891 // find a new check if on a new frame
892 if (sv.time - sv.lastchecktime >= 0.1)
894 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
895 sv.lastchecktime = sv.time;
898 // return check if it might be visible
899 ent = EDICT_NUM(sv.lastcheck);
900 if (ent->e->free || ent->v->health <= 0)
902 RETURN_EDICT(sv.edicts);
906 // if current entity can't possibly see the check entity, return 0
907 self = PROG_TO_EDICT(pr_global_struct->self);
908 VectorAdd (self->v->origin, self->v->view_ofs, view);
909 leaf = sv.worldmodel->PointInLeaf(sv.worldmodel, view);
912 l = (leaf - sv.worldmodel->leafs) - 1;
913 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
916 RETURN_EDICT(sv.edicts);
921 // might be able to see it
926 //============================================================================
933 Sends text over to the client's execution buffer
935 stuffcmd (clientent, value)
938 void PF_stuffcmd (void)
944 entnum = G_EDICTNUM(OFS_PARM0);
945 if (entnum < 1 || entnum > svs.maxclients)
946 Host_Error ("Parm 0 not a client");
947 str = G_STRING(OFS_PARM1);
950 host_client = &svs.clients[entnum-1];
951 Host_ClientCommands ("%s", str);
959 Sends text over to the client's execution buffer
964 void PF_localcmd (void)
968 str = G_STRING(OFS_PARM0);
983 str = G_STRING(OFS_PARM0);
985 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
995 void PF_cvar_set (void)
999 var = G_STRING(OFS_PARM0);
1000 val = G_STRING(OFS_PARM1);
1002 Cvar_Set (var, val);
1009 Returns a chain of entities that have origins within a spherical area
1011 findradius (origin, radius)
1014 void PF_findradius (void)
1016 edict_t *ent, *chain;
1023 chain = (edict_t *)sv.edicts;
1025 org = G_VECTOR(OFS_PARM0);
1026 radius = G_FLOAT(OFS_PARM1);
1027 radius2 = radius * radius;
1029 ent = NEXT_EDICT(sv.edicts);
1030 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1032 pr_xfunction->builtinsprofile++;
1035 if (ent->v->solid == SOLID_NOT)
1038 // LordHavoc: compare against bounding box rather than center,
1039 // and use DotProduct instead of Length, major speedup
1040 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1041 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1042 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1043 if (DotProduct(eorg, eorg) > radius2)
1046 ent->v->chain = EDICT_TO_PROG(chain);
1050 RETURN_EDICT(chain);
1059 void PF_dprint (void)
1061 Con_DPrintf ("%s",PF_VarString(0));
1064 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1065 #define STRINGTEMP_BUFFERS 16
1066 #define STRINGTEMP_LENGTH 128
1067 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1068 static int pr_string_tempindex = 0;
1070 static char *PR_GetTempString(void)
1073 s = pr_string_temp[pr_string_tempindex];
1074 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1082 v = G_FLOAT(OFS_PARM0);
1084 s = PR_GetTempString();
1085 // LordHavoc: ftos improvement
1086 sprintf (s, "%g", v);
1087 G_INT(OFS_RETURN) = PR_SetString(s);
1093 v = G_FLOAT(OFS_PARM0);
1094 G_FLOAT(OFS_RETURN) = fabs(v);
1100 s = PR_GetTempString();
1101 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1102 G_INT(OFS_RETURN) = PR_SetString(s);
1108 s = PR_GetTempString();
1109 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1110 G_INT(OFS_RETURN) = PR_SetString(s);
1113 void PF_Spawn (void)
1116 pr_xfunction->builtinsprofile += 20;
1121 void PF_Remove (void)
1124 pr_xfunction->builtinsprofile += 20;
1126 ed = G_EDICT(OFS_PARM0);
1127 if (ed == sv.edicts)
1128 Host_Error("remove: tried to remove world\n");
1129 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1130 Host_Error("remove: tried to remove a client\n");
1135 // entity (entity start, .string field, string match) find = #5;
1143 e = G_EDICTNUM(OFS_PARM0);
1144 f = G_INT(OFS_PARM1);
1145 s = G_STRING(OFS_PARM2);
1148 RETURN_EDICT(sv.edicts);
1152 for (e++ ; e < sv.num_edicts ; e++)
1154 pr_xfunction->builtinsprofile++;
1168 RETURN_EDICT(sv.edicts);
1171 // LordHavoc: added this for searching float, int, and entity reference fields
1172 void PF_FindFloat (void)
1179 e = G_EDICTNUM(OFS_PARM0);
1180 f = G_INT(OFS_PARM1);
1181 s = G_FLOAT(OFS_PARM2);
1183 for (e++ ; e < sv.num_edicts ; e++)
1185 pr_xfunction->builtinsprofile++;
1189 if (E_FLOAT(ed,f) == s)
1196 RETURN_EDICT(sv.edicts);
1199 // chained search for strings in entity fields
1200 // entity(.string field, string match) findchain = #402;
1201 void PF_findchain (void)
1206 edict_t *ent, *chain;
1208 chain = (edict_t *)sv.edicts;
1210 f = G_INT(OFS_PARM0);
1211 s = G_STRING(OFS_PARM1);
1214 RETURN_EDICT(sv.edicts);
1218 ent = NEXT_EDICT(sv.edicts);
1219 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1221 pr_xfunction->builtinsprofile++;
1224 t = E_STRING(ent,f);
1230 ent->v->chain = EDICT_TO_PROG(chain);
1234 RETURN_EDICT(chain);
1237 // LordHavoc: chained search for float, int, and entity reference fields
1238 // entity(.string field, float match) findchainfloat = #403;
1239 void PF_findchainfloat (void)
1244 edict_t *ent, *chain;
1246 chain = (edict_t *)sv.edicts;
1248 f = G_INT(OFS_PARM0);
1249 s = G_FLOAT(OFS_PARM1);
1251 ent = NEXT_EDICT(sv.edicts);
1252 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1254 pr_xfunction->builtinsprofile++;
1257 if (E_FLOAT(ent,f) != s)
1260 ent->v->chain = EDICT_TO_PROG(chain);
1264 RETURN_EDICT(chain);
1267 void PR_CheckEmptyString (char *s)
1270 Host_Error ("Bad string");
1273 void PF_precache_file (void)
1274 { // precache_file is only used to copy files with qcc, it does nothing
1275 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1278 void PF_precache_sound (void)
1283 if (sv.state != ss_loading)
1284 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1286 s = G_STRING(OFS_PARM0);
1287 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1288 PR_CheckEmptyString (s);
1290 for (i=0 ; i<MAX_SOUNDS ; i++)
1292 if (!sv.sound_precache[i])
1294 sv.sound_precache[i] = s;
1297 if (!strcmp(sv.sound_precache[i], s))
1300 Host_Error ("PF_precache_sound: overflow");
1303 void PF_precache_model (void)
1308 if (sv.state != ss_loading)
1309 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1311 s = G_STRING(OFS_PARM0);
1312 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1314 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1315 PR_CheckEmptyString (s);
1317 for (i=0 ; i<MAX_MODELS ; i++)
1319 if (!sv.model_precache[i])
1321 sv.model_precache[i] = s;
1322 sv.models[i] = Mod_ForName (s, true, false, false);
1325 if (!strcmp(sv.model_precache[i], s))
1328 Host_Error ("PF_precache_model: overflow");
1332 void PF_coredump (void)
1337 void PF_traceon (void)
1342 void PF_traceoff (void)
1347 void PF_eprint (void)
1349 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1356 float(float yaw, float dist) walkmove
1359 void PF_walkmove (void)
1367 ent = PROG_TO_EDICT(pr_global_struct->self);
1368 yaw = G_FLOAT(OFS_PARM0);
1369 dist = G_FLOAT(OFS_PARM1);
1371 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1373 G_FLOAT(OFS_RETURN) = 0;
1377 yaw = yaw*M_PI*2 / 360;
1379 move[0] = cos(yaw)*dist;
1380 move[1] = sin(yaw)*dist;
1383 // save program state, because SV_movestep may call other progs
1384 oldf = pr_xfunction;
1385 oldself = pr_global_struct->self;
1387 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1390 // restore program state
1391 pr_xfunction = oldf;
1392 pr_global_struct->self = oldself;
1402 void PF_droptofloor (void)
1408 ent = PROG_TO_EDICT(pr_global_struct->self);
1410 VectorCopy (ent->v->origin, end);
1413 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1415 if (trace.fraction == 1)
1416 G_FLOAT(OFS_RETURN) = 0;
1419 VectorCopy (trace.endpos, ent->v->origin);
1420 SV_LinkEdict (ent, false);
1421 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1422 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1423 G_FLOAT(OFS_RETURN) = 1;
1424 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1425 ent->e->suspendedinairflag = true;
1433 void(float style, string value) lightstyle
1436 void PF_lightstyle (void)
1443 style = G_FLOAT(OFS_PARM0);
1444 val = G_STRING(OFS_PARM1);
1446 // change the string in sv
1447 sv.lightstyles[style] = val;
1449 // send message to all clients on this server
1450 if (sv.state != ss_active)
1453 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1454 if (client->active || client->spawned)
1456 MSG_WriteChar (&client->message, svc_lightstyle);
1457 MSG_WriteChar (&client->message,style);
1458 MSG_WriteString (&client->message, val);
1465 f = G_FLOAT(OFS_PARM0);
1467 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1469 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1471 void PF_floor (void)
1473 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1477 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1486 void PF_checkbottom (void)
1488 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1496 void PF_pointcontents (void)
1498 G_FLOAT(OFS_RETURN) = sv.worldmodel->PointContents(sv.worldmodel, G_VECTOR(OFS_PARM0));
1505 entity nextent(entity)
1508 void PF_nextent (void)
1513 i = G_EDICTNUM(OFS_PARM0);
1516 pr_xfunction->builtinsprofile++;
1518 if (i == sv.num_edicts)
1520 RETURN_EDICT(sv.edicts);
1536 Pick a vector for the player to shoot along
1537 vector aim(entity, missilespeed)
1542 edict_t *ent, *check, *bestent;
1543 vec3_t start, dir, end, bestdir;
1546 float dist, bestdist;
1549 ent = G_EDICT(OFS_PARM0);
1550 speed = G_FLOAT(OFS_PARM1);
1552 VectorCopy (ent->v->origin, start);
1555 // try sending a trace straight
1556 VectorCopy (pr_global_struct->v_forward, dir);
1557 VectorMA (start, 2048, dir, end);
1558 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1559 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1560 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1562 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1567 // try all possible entities
1568 VectorCopy (dir, bestdir);
1569 bestdist = sv_aim.value;
1572 check = NEXT_EDICT(sv.edicts);
1573 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1575 pr_xfunction->builtinsprofile++;
1576 if (check->v->takedamage != DAMAGE_AIM)
1580 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1581 continue; // don't aim at teammate
1582 for (j=0 ; j<3 ; j++)
1583 end[j] = check->v->origin[j]
1584 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1585 VectorSubtract (end, start, dir);
1586 VectorNormalize (dir);
1587 dist = DotProduct (dir, pr_global_struct->v_forward);
1588 if (dist < bestdist)
1589 continue; // to far to turn
1590 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1591 if (tr.ent == check)
1592 { // can shoot at this one
1600 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1601 dist = DotProduct (dir, pr_global_struct->v_forward);
1602 VectorScale (pr_global_struct->v_forward, dist, end);
1604 VectorNormalize (end);
1605 VectorCopy (end, G_VECTOR(OFS_RETURN));
1609 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1617 This was a major timewaster in progs, so it was converted to C
1620 void PF_changeyaw (void)
1623 float ideal, current, move, speed;
1625 ent = PROG_TO_EDICT(pr_global_struct->self);
1626 current = ANGLEMOD(ent->v->angles[1]);
1627 ideal = ent->v->ideal_yaw;
1628 speed = ent->v->yaw_speed;
1630 if (current == ideal)
1632 move = ideal - current;
1633 if (ideal > current)
1654 ent->v->angles[1] = ANGLEMOD (current + move);
1662 void PF_changepitch (void)
1665 float ideal, current, move, speed;
1668 ent = G_EDICT(OFS_PARM0);
1669 current = ANGLEMOD( ent->v->angles[0] );
1670 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1671 ideal = val->_float;
1674 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1677 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1678 speed = val->_float;
1681 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1685 if (current == ideal)
1687 move = ideal - current;
1688 if (ideal > current)
1709 ent->v->angles[0] = ANGLEMOD (current + move);
1713 ===============================================================================
1717 ===============================================================================
1720 #define MSG_BROADCAST 0 // unreliable to all
1721 #define MSG_ONE 1 // reliable to one (msg_entity)
1722 #define MSG_ALL 2 // reliable to all
1723 #define MSG_INIT 3 // write to the init string
1725 sizebuf_t *WriteDest (void)
1731 dest = G_FLOAT(OFS_PARM0);
1735 return &sv.datagram;
1738 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1739 entnum = NUM_FOR_EDICT(ent);
1740 if (entnum < 1 || entnum > svs.maxclients)
1741 Host_Error ("WriteDest: not a client");
1742 return &svs.clients[entnum-1].message;
1745 return &sv.reliable_datagram;
1751 Host_Error ("WriteDest: bad destination");
1758 void PF_WriteByte (void)
1760 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1763 void PF_WriteChar (void)
1765 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1768 void PF_WriteShort (void)
1770 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1773 void PF_WriteLong (void)
1775 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1778 void PF_WriteAngle (void)
1780 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1783 void PF_WriteCoord (void)
1785 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1788 void PF_WriteString (void)
1790 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1794 void PF_WriteEntity (void)
1796 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1799 //=============================================================================
1801 void PF_makestatic (void)
1806 ent = G_EDICT(OFS_PARM0);
1809 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1814 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1815 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1816 MSG_WriteShort (&sv.signon, ent->v->frame);
1820 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1821 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1822 MSG_WriteByte (&sv.signon, ent->v->frame);
1825 MSG_WriteByte (&sv.signon, ent->v->colormap);
1826 MSG_WriteByte (&sv.signon, ent->v->skin);
1827 for (i=0 ; i<3 ; i++)
1829 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1830 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1833 // throw the entity away now
1837 //=============================================================================
1844 void PF_setspawnparms (void)
1850 ent = G_EDICT(OFS_PARM0);
1851 i = NUM_FOR_EDICT(ent);
1852 if (i < 1 || i > svs.maxclients)
1853 Host_Error ("Entity is not a client");
1855 // copy spawn parms out of the client_t
1856 client = svs.clients + (i-1);
1858 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1859 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1867 void PF_changelevel (void)
1871 // make sure we don't issue two changelevels
1872 if (svs.changelevel_issued)
1874 svs.changelevel_issued = true;
1876 s = G_STRING(OFS_PARM0);
1877 Cbuf_AddText (va("changelevel %s\n",s));
1882 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1887 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1892 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1899 Returns a vector of length < 1
1904 void PF_randomvec (void)
1909 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1910 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1911 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1913 while (DotProduct(temp, temp) >= 1);
1914 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1917 void SV_LightPoint (vec3_t color, vec3_t p);
1922 Returns a color vector indicating the lighting at the requested point.
1924 (Internal Operation note: actually measures the light beneath the point, just like
1925 the model lighting on the client)
1930 void PF_GetLight (void)
1934 p = G_VECTOR(OFS_PARM0);
1935 SV_LightPoint (color, p);
1936 VectorCopy (color, G_VECTOR(OFS_RETURN));
1939 #define MAX_QC_CVARS 128
1940 cvar_t qc_cvar[MAX_QC_CVARS];
1943 void PF_registercvar (void)
1947 name = G_STRING(OFS_PARM0);
1948 value = G_STRING(OFS_PARM1);
1949 G_FLOAT(OFS_RETURN) = 0;
1950 // first check to see if it has already been defined
1951 if (Cvar_FindVar (name))
1954 // check for overlap with a command
1955 if (Cmd_Exists (name))
1957 Con_Printf ("PF_registercvar: %s is a command\n", name);
1961 if (currentqc_cvar >= MAX_QC_CVARS)
1962 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1964 // copy the name and value
1965 variable = &qc_cvar[currentqc_cvar++];
1966 variable->name = Z_Malloc (strlen(name)+1);
1967 strcpy (variable->name, name);
1968 variable->string = Z_Malloc (strlen(value)+1);
1969 strcpy (variable->string, value);
1970 variable->value = atof (value);
1972 Cvar_RegisterVariable(variable);
1973 G_FLOAT(OFS_RETURN) = 1; // success
1980 returns the minimum of two supplied floats
1987 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1989 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1990 else if (pr_argc >= 3)
1993 float f = G_FLOAT(OFS_PARM0);
1994 for (i = 1;i < pr_argc;i++)
1995 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1996 f = G_FLOAT((OFS_PARM0+i*3));
1997 G_FLOAT(OFS_RETURN) = f;
2000 Host_Error("min: must supply at least 2 floats\n");
2007 returns the maximum of two supplied floats
2014 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2016 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2017 else if (pr_argc >= 3)
2020 float f = G_FLOAT(OFS_PARM0);
2021 for (i = 1;i < pr_argc;i++)
2022 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2023 f = G_FLOAT((OFS_PARM0+i*3));
2024 G_FLOAT(OFS_RETURN) = f;
2027 Host_Error("max: must supply at least 2 floats\n");
2034 returns number bounded by supplied range
2036 min(min, value, max)
2039 void PF_bound (void)
2041 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2048 returns a raised to power b
2055 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2062 copies data from one entity to another
2064 copyentity(src, dst)
2067 void PF_copyentity (void)
2070 in = G_EDICT(OFS_PARM0);
2071 out = G_EDICT(OFS_PARM1);
2072 memcpy(out->v, in->v, progs->entityfields * 4);
2079 sets the color of a client and broadcasts the update to all connected clients
2081 setcolor(clientent, value)
2084 void PF_setcolor (void)
2090 entnum = G_EDICTNUM(OFS_PARM0);
2091 i = G_FLOAT(OFS_PARM1);
2093 if (entnum < 1 || entnum > svs.maxclients)
2095 Con_Printf ("tried to setcolor a non-client\n");
2099 client = &svs.clients[entnum-1];
2100 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2103 client->old_colors = i;
2104 client->edict->v->team = (i & 15) + 1;
2106 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2107 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2108 MSG_WriteByte (&sv.reliable_datagram, i);
2115 effect(origin, modelname, startframe, framecount, framerate)
2118 void PF_effect (void)
2121 s = G_STRING(OFS_PARM1);
2123 Host_Error("effect: no model specified\n");
2125 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2128 void PF_te_blood (void)
2130 if (G_FLOAT(OFS_PARM2) < 1)
2132 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2133 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2135 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2136 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2137 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2139 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2140 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2141 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2143 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2146 void PF_te_bloodshower (void)
2148 if (G_FLOAT(OFS_PARM3) < 1)
2150 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2151 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2153 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2154 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2155 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2157 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2158 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2159 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2161 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2163 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2166 void PF_te_explosionrgb (void)
2168 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2169 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2171 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2172 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2173 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2175 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2176 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2177 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2180 void PF_te_particlecube (void)
2182 if (G_FLOAT(OFS_PARM3) < 1)
2184 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2185 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2189 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2191 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2192 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2193 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2195 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2196 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2197 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2199 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2201 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2202 // gravity true/false
2203 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2205 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2208 void PF_te_particlerain (void)
2210 if (G_FLOAT(OFS_PARM3) < 1)
2212 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2213 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2217 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2219 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2220 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2221 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2223 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2224 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2225 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2227 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2229 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2232 void PF_te_particlesnow (void)
2234 if (G_FLOAT(OFS_PARM3) < 1)
2236 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2237 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2241 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2243 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2244 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2245 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2247 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2248 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2249 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2251 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2253 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2256 void PF_te_spark (void)
2258 if (G_FLOAT(OFS_PARM2) < 1)
2260 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2261 MSG_WriteByte(&sv.datagram, TE_SPARK);
2263 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2264 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2267 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2268 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2269 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2271 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2274 void PF_te_gunshotquad (void)
2276 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2277 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2279 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2280 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2284 void PF_te_spikequad (void)
2286 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2287 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2289 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2290 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2294 void PF_te_superspikequad (void)
2296 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2297 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2299 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2300 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2301 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2304 void PF_te_explosionquad (void)
2306 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2307 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2309 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2310 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2314 void PF_te_smallflash (void)
2316 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2317 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2319 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2320 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2321 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2324 void PF_te_customflash (void)
2326 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2328 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2329 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2331 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2332 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2333 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2335 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2337 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2339 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2340 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2341 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2344 void PF_te_gunshot (void)
2346 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2347 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2349 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2350 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2354 void PF_te_spike (void)
2356 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2357 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2359 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2360 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2364 void PF_te_superspike (void)
2366 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2367 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2369 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2370 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2374 void PF_te_explosion (void)
2376 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2377 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2379 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2380 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2381 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2384 void PF_te_tarexplosion (void)
2386 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2387 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2389 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2390 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2394 void PF_te_wizspike (void)
2396 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2399 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2400 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2404 void PF_te_knightspike (void)
2406 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2407 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2409 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2410 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2414 void PF_te_lavasplash (void)
2416 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2417 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2419 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2420 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2424 void PF_te_teleport (void)
2426 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2427 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2429 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2430 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2434 void PF_te_explosion2 (void)
2436 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2437 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2439 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2440 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2441 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2443 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2446 void PF_te_lightning1 (void)
2448 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2449 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2451 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2453 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2454 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2455 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2457 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2458 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2462 void PF_te_lightning2 (void)
2464 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2465 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2467 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2469 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2470 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2473 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2474 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2478 void PF_te_lightning3 (void)
2480 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2481 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2483 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2485 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2486 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2487 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2489 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2490 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2494 void PF_te_beam (void)
2496 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2497 MSG_WriteByte(&sv.datagram, TE_BEAM);
2499 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2501 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2502 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2503 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2505 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2510 void PF_te_plasmaburn (void)
2512 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2513 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2514 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2515 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2516 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2519 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2522 vec3_t v1, clipplanenormal, normal;
2523 vec_t clipplanedist, clipdist;
2525 if (surf->flags & SURF_PLANEBACK)
2526 VectorNegate(surf->plane->normal, normal);
2528 VectorCopy(surf->plane->normal, normal);
2529 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2531 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2532 VectorNormalizeFast(v1);
2533 CrossProduct(v1, normal, clipplanenormal);
2534 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2535 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2538 clipdist = -clipdist;
2539 VectorMA(out, clipdist, clipplanenormal, out);
2544 static msurface_t *getsurface(edict_t *ed, int surfnum)
2548 if (!ed || ed->e->free)
2550 modelindex = ed->v->modelindex;
2551 if (modelindex < 1 || modelindex >= MAX_MODELS)
2553 model = sv.models[modelindex];
2554 if (model->type != mod_brush)
2556 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2558 return model->surfaces + surfnum + model->firstmodelsurface;
2562 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2563 void PF_getsurfacenumpoints(void)
2566 // return 0 if no such surface
2567 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2569 G_FLOAT(OFS_RETURN) = 0;
2573 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2575 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2576 void PF_getsurfacepoint(void)
2581 VectorClear(G_VECTOR(OFS_RETURN));
2582 ed = G_EDICT(OFS_PARM0);
2583 if (!ed || ed->e->free)
2585 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2587 pointnum = G_FLOAT(OFS_PARM2);
2588 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2590 // FIXME: implement rotation/scaling
2591 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2593 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2594 void PF_getsurfacenormal(void)
2597 VectorClear(G_VECTOR(OFS_RETURN));
2598 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2600 // FIXME: implement rotation/scaling
2601 if (surf->flags & SURF_PLANEBACK)
2602 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2604 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2606 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2607 void PF_getsurfacetexture(void)
2610 G_INT(OFS_RETURN) = 0;
2611 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2613 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2615 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2616 void PF_getsurfacenearpoint(void)
2618 int surfnum, best, modelindex;
2620 vec_t dist, bestdist;
2625 G_FLOAT(OFS_RETURN) = -1;
2626 ed = G_EDICT(OFS_PARM0);
2627 point = G_VECTOR(OFS_PARM1);
2629 if (!ed || ed->e->free)
2631 modelindex = ed->v->modelindex;
2632 if (modelindex < 1 || modelindex >= MAX_MODELS)
2634 model = sv.models[modelindex];
2635 if (model->type != mod_brush)
2638 // FIXME: implement rotation/scaling
2639 VectorSubtract(point, ed->v->origin, p);
2641 bestdist = 1000000000;
2642 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2644 surf = model->surfaces + surfnum + model->firstmodelsurface;
2645 dist = PlaneDiff(p, surf->plane);
2647 if (dist < bestdist)
2649 clippointtosurface(surf, p, clipped);
2650 VectorSubtract(clipped, p, clipped);
2651 dist += DotProduct(clipped, clipped);
2652 if (dist < bestdist)
2659 G_FLOAT(OFS_RETURN) = best;
2661 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2662 void PF_getsurfaceclippedpoint(void)
2667 VectorClear(G_VECTOR(OFS_RETURN));
2668 ed = G_EDICT(OFS_PARM0);
2669 if (!ed || ed->e->free)
2671 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2673 // FIXME: implement rotation/scaling
2674 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2675 clippointtosurface(surf, p, out);
2676 // FIXME: implement rotation/scaling
2677 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2680 #define MAX_PRFILES 256
2682 qfile_t *pr_files[MAX_PRFILES];
2684 void PR_Files_Init(void)
2686 memset(pr_files, 0, sizeof(pr_files));
2689 void PR_Files_CloseAll(void)
2692 for (i = 0;i < MAX_PRFILES;i++)
2695 FS_Close(pr_files[i]);
2700 //float(string s) stof = #81; // get numerical value from a string
2703 char *s = PF_VarString(0);
2704 G_FLOAT(OFS_RETURN) = atof(s);
2707 //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
2711 char *modestring, *filename;
2712 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2713 if (pr_files[filenum] == NULL)
2715 if (filenum >= MAX_PRFILES)
2717 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2718 G_FLOAT(OFS_RETURN) = -2;
2721 mode = G_FLOAT(OFS_PARM1);
2724 case 0: // FILE_READ
2727 case 1: // FILE_APPEND
2730 case 2: // FILE_WRITE
2734 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2735 G_FLOAT(OFS_RETURN) = -3;
2738 filename = G_STRING(OFS_PARM0);
2739 // .. is parent directory on many platforms
2740 // / is parent directory on Amiga
2741 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2742 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2743 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2745 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2746 G_FLOAT(OFS_RETURN) = -4;
2749 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2750 if (pr_files[filenum] == NULL)
2751 G_FLOAT(OFS_RETURN) = -1;
2753 G_FLOAT(OFS_RETURN) = filenum;
2756 //void(float fhandle) fclose = #111; // closes a file
2757 void PF_fclose(void)
2759 int filenum = G_FLOAT(OFS_PARM0);
2760 if (filenum < 0 || filenum >= MAX_PRFILES)
2762 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2765 if (pr_files[filenum] == NULL)
2767 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2770 FS_Close(pr_files[filenum]);
2771 pr_files[filenum] = NULL;
2774 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2778 static char string[MAX_VARSTRING];
2779 int filenum = G_FLOAT(OFS_PARM0);
2780 if (filenum < 0 || filenum >= MAX_PRFILES)
2782 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2785 if (pr_files[filenum] == NULL)
2787 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2793 c = FS_Getc(pr_files[filenum]);
2794 if (c == '\r' || c == '\n' || c < 0)
2796 if (end < MAX_VARSTRING - 1)
2800 // remove \n following \r
2802 c = FS_Getc(pr_files[filenum]);
2803 if (developer.integer)
2804 Con_Printf("fgets: %s\n", string);
2806 G_INT(OFS_RETURN) = PR_SetString(string);
2808 G_INT(OFS_RETURN) = 0;
2811 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2815 char *s = PF_VarString(1);
2816 int filenum = G_FLOAT(OFS_PARM0);
2817 if (filenum < 0 || filenum >= MAX_PRFILES)
2819 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2822 if (pr_files[filenum] == NULL)
2824 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2827 if ((stringlength = strlen(s)))
2828 FS_Write(pr_files[filenum], s, stringlength);
2829 if (developer.integer)
2830 Con_Printf("fputs: %s\n", s);
2833 //float(string s) strlen = #114; // returns how many characters are in a string
2834 void PF_strlen(void)
2837 s = G_STRING(OFS_PARM0);
2839 G_FLOAT(OFS_RETURN) = strlen(s);
2841 G_FLOAT(OFS_RETURN) = 0;
2844 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2845 void PF_strcat(void)
2847 char *s = PF_VarString(0);
2848 G_INT(OFS_RETURN) = PR_SetString(s);
2851 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2852 void PF_substring(void)
2855 char *s, string[MAX_VARSTRING];
2856 s = G_STRING(OFS_PARM0);
2857 start = G_FLOAT(OFS_PARM1);
2858 end = G_FLOAT(OFS_PARM2) + start;
2861 for (i = 0;i < start && *s;i++, s++);
2862 for (i = 0;i < MAX_VARSTRING - 1 && *s && i < end;i++, s++)
2865 G_INT(OFS_RETURN) = PR_SetString(string);
2868 //vector(string s) stov = #117; // returns vector value from a string
2871 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2874 //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)
2875 void PF_strzone(void)
2878 in = G_STRING(OFS_PARM0);
2879 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2881 G_INT(OFS_RETURN) = PR_SetString(out);
2884 //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!!!)
2885 void PF_strunzone(void)
2887 Mem_Free(G_STRING(OFS_PARM0));
2890 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2891 //this function originally written by KrimZon, made shorter by LordHavoc
2892 void PF_clientcommand (void)
2894 client_t *temp_client;
2897 //find client for this entity
2898 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2899 if (i < 0 || i >= svs.maxclients)
2900 Host_Error("PF_clientcommand: entity is not a client");
2902 temp_client = host_client;
2903 host_client = &svs.clients[i];
2904 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2905 host_client = temp_client;
2908 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2909 //this function originally written by KrimZon, made shorter by LordHavoc
2910 char **tokens = NULL;
2911 int max_tokens, num_tokens = 0;
2912 void PF_tokenize (void)
2916 str = G_STRING(OFS_PARM0);
2921 for (i=0;i<num_tokens;i++)
2927 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2928 max_tokens = strlen(str);
2930 for (p = str;COM_ParseToken(&p) && num_tokens < max_tokens;num_tokens++)
2932 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2933 strcpy(tokens[num_tokens], com_token);
2936 G_FLOAT(OFS_RETURN) = num_tokens;
2939 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2940 //this function originally written by KrimZon, made shorter by LordHavoc
2943 int token_num = G_FLOAT(OFS_PARM0);
2944 if (token_num >= 0 && token_num < num_tokens)
2945 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2947 G_INT(OFS_RETURN) = PR_SetString("");
2951 builtin_t pr_builtin[] =
2954 PF_makevectors, // #1 void(entity e) makevectors
2955 PF_setorigin, // #2 void(entity e, vector o) setorigin
2956 PF_setmodel, // #3 void(entity e, string m) setmodel
2957 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2958 NULL, // #5 void(entity e, vector min, vector max) setabssize
2959 PF_break, // #6 void() break
2960 PF_random, // #7 float() random
2961 PF_sound, // #8 void(entity e, float chan, string samp) sound
2962 PF_normalize, // #9 vector(vector v) normalize
2963 PF_error, // #10 void(string e) error
2964 PF_objerror, // #11 void(string e) objerror
2965 PF_vlen, // #12 float(vector v) vlen
2966 PF_vectoyaw, // #13 float(vector v) vectoyaw
2967 PF_Spawn, // #14 entity() spawn
2968 PF_Remove, // #15 void(entity e) remove
2969 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2970 PF_checkclient, // #17 entity() clientlist
2971 PF_Find, // #18 entity(entity start, .string fld, string match) find
2972 PF_precache_sound, // #19 void(string s) precache_sound
2973 PF_precache_model, // #20 void(string s) precache_model
2974 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2975 PF_findradius, // #22 entity(vector org, float rad) findradius
2976 PF_bprint, // #23 void(string s) bprint
2977 PF_sprint, // #24 void(entity client, string s) sprint
2978 PF_dprint, // #25 void(string s) dprint
2979 PF_ftos, // #26 void(string s) ftos
2980 PF_vtos, // #27 void(string s) vtos
2981 PF_coredump, // #28 void() coredump
2982 PF_traceon, // #29 void() traceon
2983 PF_traceoff, // #30 void() traceoff
2984 PF_eprint, // #31 void(entity e) eprint
2985 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2987 PF_droptofloor, // #34 float() droptofloor
2988 PF_lightstyle, // #35 void(float style, string value) lightstyle
2989 PF_rint, // #36 float(float v) rint
2990 PF_floor, // #37 float(float v) floor
2991 PF_ceil, // #38 float(float v) ceil
2993 PF_checkbottom, // #40 float(entity e) checkbottom
2994 PF_pointcontents , // #41 float(vector v) pointcontents
2996 PF_fabs, // #43 float(float f) fabs
2997 PF_aim, // #44 vector(entity e, float speed) aim
2998 PF_cvar, // #45 float(string s) cvar
2999 PF_localcmd, // #46 void(string s) localcmd
3000 PF_nextent, // #47 entity(entity e) nextent
3001 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3002 PF_changeyaw, // #49 void() ChangeYaw
3004 PF_vectoangles, // #51 vector(vector v) vectoangles
3005 PF_WriteByte, // #52 void(float to, float f) WriteByte
3006 PF_WriteChar, // #53 void(float to, float f) WriteChar
3007 PF_WriteShort, // #54 void(float to, float f) WriteShort
3008 PF_WriteLong, // #55 void(float to, float f) WriteLong
3009 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3010 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3011 PF_WriteString, // #58 void(float to, string s) WriteString
3012 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3013 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3014 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3015 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3016 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3017 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3018 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3020 SV_MoveToGoal, // #67 void(float step) movetogoal
3021 PF_precache_file, // #68 string(string s) precache_file
3022 PF_makestatic, // #69 void(entity e) makestatic
3023 PF_changelevel, // #70 void(string s) changelevel
3025 PF_cvar_set, // #72 void(string var, string val) cvar_set
3026 PF_centerprint, // #73 void(entity client, strings) centerprint
3027 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3028 PF_precache_model, // #75 string(string s) precache_model2
3029 PF_precache_sound, // #76 string(string s) precache_sound2
3030 PF_precache_file, // #77 string(string s) precache_file2
3031 PF_setspawnparms, // #78 void(entity e) setspawnparms
3034 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3043 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3044 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3045 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3046 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3047 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3048 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3049 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3050 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3051 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3052 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3063 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3064 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3065 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3066 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3067 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3068 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3069 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3070 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3071 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3072 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3073 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3074 a a a a a a a a // #120-199
3075 a a a a a a a a a a // #200-299
3076 a a a a a a a a a a // #300-399
3077 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3078 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3079 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3080 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3081 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3082 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3083 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3084 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3085 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3086 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3087 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3088 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3089 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3090 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3091 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3092 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3093 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3094 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3095 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3096 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3097 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3098 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3099 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3100 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3101 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3102 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3103 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3104 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3105 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3106 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3107 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3108 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3109 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3110 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3111 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3112 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3113 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3114 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3115 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3116 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3117 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3118 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3119 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3127 a a a a a // #450-499 (LordHavoc)
3130 builtin_t *pr_builtins = pr_builtin;
3131 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3133 void PR_Cmd_Init(void)
3135 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3139 void PR_Cmd_Reset(void)
3141 Mem_EmptyPool(pr_strings_mempool);
3142 PR_Files_CloseAll();