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 "
80 "DP_GFX_EXTERNALTEXTURES "
84 "DP_MOVETYPEBOUNCEMISSILE "
90 "DP_QC_FINDCHAINFLOAT "
96 "DP_QC_SINCOSSQRTPOW "
99 "DP_QC_VECTORVECTORS "
105 "DP_SV_DRAWONLYTOCLIENT "
107 "DP_SV_EXTERIORMODELTOCLIENT "
108 "DP_SV_NODRAWTOCLIENT "
109 "DP_SV_PLAYERPHYSICS "
115 "DP_TE_EXPLOSIONRGB "
117 "DP_TE_PARTICLECUBE "
118 "DP_TE_PARTICLERAIN "
119 "DP_TE_PARTICLESNOW "
121 "DP_TE_QUADEFFECTS1 "
124 "DP_TE_STANDARDEFFECTBUILTINS "
127 "KRIMZON_SV_PARSECLIENTCOMMAND "
133 qboolean checkextension(char *name)
138 for (e = ENGINE_EXTENSIONS;*e;e++)
145 while (*e && *e != ' ')
147 if (e - start == len)
148 if (!strncasecmp(start, name, len))
158 returns true if the extension is supported by the server
160 checkextension(extensionname)
163 void PF_checkextension (void)
165 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
172 This is a TERMINAL error, which will kill off the entire server.
184 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
185 ed = PROG_TO_EDICT(pr_global_struct->self);
188 Host_Error ("Program error");
195 Dumps out self, then an error message. The program is aborted and self is
196 removed, but the level can continue.
201 void PF_objerror (void)
207 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
208 ed = PROG_TO_EDICT(pr_global_struct->self);
218 Writes new values for v_forward, v_up, and v_right based on angles
222 void PF_makevectors (void)
224 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
231 Writes new values for v_forward, v_up, and v_right based on the given forward vector
232 vectorvectors(vector, vector)
235 void PF_vectorvectors (void)
237 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
238 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
245 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.
247 setorigin (entity, origin)
250 void PF_setorigin (void)
255 e = G_EDICT(OFS_PARM0);
256 org = G_VECTOR(OFS_PARM1);
257 VectorCopy (org, e->v->origin);
258 SV_LinkEdict (e, false);
262 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
266 for (i=0 ; i<3 ; i++)
268 Host_Error ("backwards mins/maxs");
270 // set derived values
271 VectorCopy (min, e->v->mins);
272 VectorCopy (max, e->v->maxs);
273 VectorSubtract (max, min, e->v->size);
275 SV_LinkEdict (e, false);
282 the size box is rotated by the current angle
283 LordHavoc: no it isn't...
285 setsize (entity, minvector, maxvector)
288 void PF_setsize (void)
293 e = G_EDICT(OFS_PARM0);
294 min = G_VECTOR(OFS_PARM1);
295 max = G_VECTOR(OFS_PARM2);
296 SetMinMaxSize (e, min, max, false);
304 setmodel(entity, model)
307 void PF_setmodel (void)
314 e = G_EDICT(OFS_PARM0);
315 m = G_STRING(OFS_PARM1);
317 // check to see if model was properly precached
318 for (i=0, check = sv.model_precache ; *check ; i++, check++)
319 if (!strcmp(*check, m))
323 Host_Error ("no precache: %s\n", m);
326 e->v->model = PR_SetString(*check);
327 e->v->modelindex = i;
329 mod = sv.models[ (int)e->v->modelindex];
332 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
334 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
341 broadcast print to everyone on server
346 void PF_bprint (void)
351 SV_BroadcastPrintf ("%s", s);
358 single print to a specific client
360 sprint(clientent, value)
363 void PF_sprint (void)
369 entnum = G_EDICTNUM(OFS_PARM0);
372 if (entnum < 1 || entnum > svs.maxclients)
374 Con_Printf ("tried to sprint to a non-client\n");
378 client = &svs.clients[entnum-1];
380 MSG_WriteChar (&client->message,svc_print);
381 MSG_WriteString (&client->message, s );
389 single print to a specific client
391 centerprint(clientent, value)
394 void PF_centerprint (void)
400 entnum = G_EDICTNUM(OFS_PARM0);
403 if (entnum < 1 || entnum > svs.maxclients)
405 Con_Printf ("tried to sprint to a non-client\n");
409 client = &svs.clients[entnum-1];
411 MSG_WriteChar (&client->message,svc_centerprint);
412 MSG_WriteString (&client->message, s );
420 vector normalize(vector)
423 void PF_normalize (void)
429 value1 = G_VECTOR(OFS_PARM0);
431 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
435 newvalue[0] = newvalue[1] = newvalue[2] = 0;
439 newvalue[0] = value1[0] * new;
440 newvalue[1] = value1[1] * new;
441 newvalue[2] = value1[2] * new;
444 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
459 value1 = G_VECTOR(OFS_PARM0);
461 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
464 G_FLOAT(OFS_RETURN) = new;
471 float vectoyaw(vector)
474 void PF_vectoyaw (void)
479 value1 = G_VECTOR(OFS_PARM0);
481 if (value1[1] == 0 && value1[0] == 0)
485 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
490 G_FLOAT(OFS_RETURN) = yaw;
498 vector vectoangles(vector)
501 void PF_vectoangles (void)
507 value1 = G_VECTOR(OFS_PARM0);
509 if (value1[1] == 0 && value1[0] == 0)
519 // LordHavoc: optimized a bit
522 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
526 else if (value1[1] > 0)
531 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
532 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
537 G_FLOAT(OFS_RETURN+0) = pitch;
538 G_FLOAT(OFS_RETURN+1) = yaw;
539 G_FLOAT(OFS_RETURN+2) = 0;
546 Returns a number from 0<= num < 1
551 void PF_random (void)
555 num = (rand ()&0x7fff) / ((float)0x7fff);
557 G_FLOAT(OFS_RETURN) = num;
564 particle(origin, color, count)
567 void PF_particle (void)
573 org = G_VECTOR(OFS_PARM0);
574 dir = G_VECTOR(OFS_PARM1);
575 color = G_FLOAT(OFS_PARM2);
576 count = G_FLOAT(OFS_PARM3);
577 SV_StartParticle (org, dir, color, count);
587 void PF_ambientsound (void)
592 float vol, attenuation;
593 int i, soundnum, large;
595 pos = G_VECTOR (OFS_PARM0);
596 samp = G_STRING(OFS_PARM1);
597 vol = G_FLOAT(OFS_PARM2);
598 attenuation = G_FLOAT(OFS_PARM3);
600 // check to see if samp was properly precached
601 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
602 if (!strcmp(*check,samp))
607 Con_Printf ("no precache: %s\n", samp);
615 // add an svc_spawnambient command to the level signon packet
618 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
620 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
622 for (i=0 ; i<3 ; i++)
623 MSG_WriteDPCoord(&sv.signon, pos[i]);
626 MSG_WriteShort (&sv.signon, soundnum);
628 MSG_WriteByte (&sv.signon, soundnum);
630 MSG_WriteByte (&sv.signon, vol*255);
631 MSG_WriteByte (&sv.signon, attenuation*64);
639 Each entity can have eight independant sound sources, like voice,
642 Channel 0 is an auto-allocate channel, the others override anything
643 already running on that entity/channel pair.
645 An attenuation of 0 will play full volume everywhere in the level.
646 Larger attenuations will drop off.
658 entity = G_EDICT(OFS_PARM0);
659 channel = G_FLOAT(OFS_PARM1);
660 sample = G_STRING(OFS_PARM2);
661 volume = G_FLOAT(OFS_PARM3) * 255;
662 attenuation = G_FLOAT(OFS_PARM4);
664 if (volume < 0 || volume > 255)
665 Host_Error ("SV_StartSound: volume = %i", volume);
667 if (attenuation < 0 || attenuation > 4)
668 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
670 if (channel < 0 || channel > 7)
671 Host_Error ("SV_StartSound: channel = %i", channel);
673 SV_StartSound (entity, channel, sample, volume, attenuation);
685 Host_Error ("break statement");
692 Used for use tracing and shot targeting
693 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
694 if the tryents flag is set.
696 traceline (vector1, vector2, tryents)
699 void PF_traceline (void)
706 pr_xfunction->builtinsprofile += 30;
708 v1 = G_VECTOR(OFS_PARM0);
709 v2 = G_VECTOR(OFS_PARM1);
710 nomonsters = G_FLOAT(OFS_PARM2);
711 ent = G_EDICT(OFS_PARM3);
713 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
715 pr_global_struct->trace_allsolid = trace.allsolid;
716 pr_global_struct->trace_startsolid = trace.startsolid;
717 pr_global_struct->trace_fraction = trace.fraction;
718 pr_global_struct->trace_inwater = trace.inwater;
719 pr_global_struct->trace_inopen = trace.inopen;
720 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
721 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
722 pr_global_struct->trace_plane_dist = trace.plane.dist;
724 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
726 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
727 // FIXME: add trace_endcontents
735 Used for use tracing and shot targeting
736 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
737 if the tryents flag is set.
739 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
742 // LordHavoc: added this for my own use, VERY useful, similar to traceline
743 void PF_tracebox (void)
745 float *v1, *v2, *m1, *m2;
750 pr_xfunction->builtinsprofile += 30;
752 v1 = G_VECTOR(OFS_PARM0);
753 m1 = G_VECTOR(OFS_PARM1);
754 m2 = G_VECTOR(OFS_PARM2);
755 v2 = G_VECTOR(OFS_PARM3);
756 nomonsters = G_FLOAT(OFS_PARM4);
757 ent = G_EDICT(OFS_PARM5);
759 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
761 pr_global_struct->trace_allsolid = trace.allsolid;
762 pr_global_struct->trace_startsolid = trace.startsolid;
763 pr_global_struct->trace_fraction = trace.fraction;
764 pr_global_struct->trace_inwater = trace.inwater;
765 pr_global_struct->trace_inopen = trace.inopen;
766 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
767 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
768 pr_global_struct->trace_plane_dist = trace.plane.dist;
770 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
772 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
775 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
776 void PF_TraceToss (void)
782 pr_xfunction->builtinsprofile += 600;
784 ent = G_EDICT(OFS_PARM0);
785 ignore = G_EDICT(OFS_PARM1);
787 trace = SV_Trace_Toss (ent, ignore);
789 pr_global_struct->trace_allsolid = trace.allsolid;
790 pr_global_struct->trace_startsolid = trace.startsolid;
791 pr_global_struct->trace_fraction = trace.fraction;
792 pr_global_struct->trace_inwater = trace.inwater;
793 pr_global_struct->trace_inopen = trace.inopen;
794 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
795 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
796 pr_global_struct->trace_plane_dist = trace.plane.dist;
798 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
800 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
808 Returns true if the given entity can move to the given position from it's
809 current position by walking or rolling.
811 scalar checkpos (entity, vector)
814 void PF_checkpos (void)
818 //============================================================================
820 qbyte checkpvs[MAX_MAP_LEAFS/8];
822 int PF_newcheckclient (int check)
828 // cycle to the next one
832 if (check > svs.maxclients)
833 check = svs.maxclients;
835 if (check == svs.maxclients)
842 pr_xfunction->builtinsprofile++;
843 if (i == svs.maxclients+1)
849 break; // didn't find anything else
853 if (ent->v->health <= 0)
855 if ((int)ent->v->flags & FL_NOTARGET)
858 // anything that is a client, or has a client as an enemy
862 // get the PVS for the entity
863 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
864 memcpy (checkpvs, sv.worldmodel->LeafPVS(sv.worldmodel, sv.worldmodel->PointInLeaf(sv.worldmodel, org)), (sv.worldmodel->numleafs+7)>>3 );
873 Returns a client (or object that has a client enemy) that would be a
876 If there is more than one valid option, they are cycled each frame
878 If (self.origin + self.viewofs) is not in the PVS of the current target,
879 it is not returned at all.
884 int c_invis, c_notvis;
885 void PF_checkclient (void)
892 // find a new check if on a new frame
893 if (sv.time - sv.lastchecktime >= 0.1)
895 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
896 sv.lastchecktime = sv.time;
899 // return check if it might be visible
900 ent = EDICT_NUM(sv.lastcheck);
901 if (ent->e->free || ent->v->health <= 0)
903 RETURN_EDICT(sv.edicts);
907 // if current entity can't possibly see the check entity, return 0
908 self = PROG_TO_EDICT(pr_global_struct->self);
909 VectorAdd (self->v->origin, self->v->view_ofs, view);
910 leaf = sv.worldmodel->PointInLeaf(sv.worldmodel, view);
913 l = (leaf - sv.worldmodel->leafs) - 1;
914 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
917 RETURN_EDICT(sv.edicts);
922 // might be able to see it
927 //============================================================================
934 Sends text over to the client's execution buffer
936 stuffcmd (clientent, value)
939 void PF_stuffcmd (void)
945 entnum = G_EDICTNUM(OFS_PARM0);
946 if (entnum < 1 || entnum > svs.maxclients)
947 Host_Error ("Parm 0 not a client");
948 str = G_STRING(OFS_PARM1);
951 host_client = &svs.clients[entnum-1];
952 Host_ClientCommands ("%s", str);
960 Sends text over to the client's execution buffer
965 void PF_localcmd (void)
969 str = G_STRING(OFS_PARM0);
984 str = G_STRING(OFS_PARM0);
986 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
996 void PF_cvar_set (void)
1000 var = G_STRING(OFS_PARM0);
1001 val = G_STRING(OFS_PARM1);
1003 Cvar_Set (var, val);
1010 Returns a chain of entities that have origins within a spherical area
1012 findradius (origin, radius)
1015 void PF_findradius (void)
1017 edict_t *ent, *chain;
1024 chain = (edict_t *)sv.edicts;
1026 org = G_VECTOR(OFS_PARM0);
1027 radius = G_FLOAT(OFS_PARM1);
1028 radius2 = radius * radius;
1030 ent = NEXT_EDICT(sv.edicts);
1031 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1033 pr_xfunction->builtinsprofile++;
1036 if (ent->v->solid == SOLID_NOT)
1039 // LordHavoc: compare against bounding box rather than center,
1040 // and use DotProduct instead of Length, major speedup
1041 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1042 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1043 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1044 if (DotProduct(eorg, eorg) > radius2)
1047 ent->v->chain = EDICT_TO_PROG(chain);
1051 RETURN_EDICT(chain);
1060 void PF_dprint (void)
1062 Con_DPrintf ("%s",PF_VarString(0));
1065 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1066 #define STRINGTEMP_BUFFERS 16
1067 #define STRINGTEMP_LENGTH 128
1068 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1069 static int pr_string_tempindex = 0;
1071 static char *PR_GetTempString(void)
1074 s = pr_string_temp[pr_string_tempindex];
1075 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1083 v = G_FLOAT(OFS_PARM0);
1085 s = PR_GetTempString();
1086 // LordHavoc: ftos improvement
1087 sprintf (s, "%g", v);
1088 G_INT(OFS_RETURN) = PR_SetString(s);
1094 v = G_FLOAT(OFS_PARM0);
1095 G_FLOAT(OFS_RETURN) = fabs(v);
1101 s = PR_GetTempString();
1102 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1103 G_INT(OFS_RETURN) = PR_SetString(s);
1109 s = PR_GetTempString();
1110 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1111 G_INT(OFS_RETURN) = PR_SetString(s);
1114 void PF_Spawn (void)
1117 pr_xfunction->builtinsprofile += 20;
1122 void PF_Remove (void)
1125 pr_xfunction->builtinsprofile += 20;
1127 ed = G_EDICT(OFS_PARM0);
1128 if (ed == sv.edicts)
1129 Host_Error("remove: tried to remove world\n");
1130 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1131 Host_Error("remove: tried to remove a client\n");
1136 // entity (entity start, .string field, string match) find = #5;
1144 e = G_EDICTNUM(OFS_PARM0);
1145 f = G_INT(OFS_PARM1);
1146 s = G_STRING(OFS_PARM2);
1149 RETURN_EDICT(sv.edicts);
1153 for (e++ ; e < sv.num_edicts ; e++)
1155 pr_xfunction->builtinsprofile++;
1169 RETURN_EDICT(sv.edicts);
1172 // LordHavoc: added this for searching float, int, and entity reference fields
1173 void PF_FindFloat (void)
1180 e = G_EDICTNUM(OFS_PARM0);
1181 f = G_INT(OFS_PARM1);
1182 s = G_FLOAT(OFS_PARM2);
1184 for (e++ ; e < sv.num_edicts ; e++)
1186 pr_xfunction->builtinsprofile++;
1190 if (E_FLOAT(ed,f) == s)
1197 RETURN_EDICT(sv.edicts);
1200 // chained search for strings in entity fields
1201 // entity(.string field, string match) findchain = #402;
1202 void PF_findchain (void)
1207 edict_t *ent, *chain;
1209 chain = (edict_t *)sv.edicts;
1211 f = G_INT(OFS_PARM0);
1212 s = G_STRING(OFS_PARM1);
1215 RETURN_EDICT(sv.edicts);
1219 ent = NEXT_EDICT(sv.edicts);
1220 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1222 pr_xfunction->builtinsprofile++;
1225 t = E_STRING(ent,f);
1231 ent->v->chain = EDICT_TO_PROG(chain);
1235 RETURN_EDICT(chain);
1238 // LordHavoc: chained search for float, int, and entity reference fields
1239 // entity(.string field, float match) findchainfloat = #403;
1240 void PF_findchainfloat (void)
1245 edict_t *ent, *chain;
1247 chain = (edict_t *)sv.edicts;
1249 f = G_INT(OFS_PARM0);
1250 s = G_FLOAT(OFS_PARM1);
1252 ent = NEXT_EDICT(sv.edicts);
1253 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1255 pr_xfunction->builtinsprofile++;
1258 if (E_FLOAT(ent,f) != s)
1261 ent->v->chain = EDICT_TO_PROG(chain);
1265 RETURN_EDICT(chain);
1268 void PR_CheckEmptyString (char *s)
1271 Host_Error ("Bad string");
1274 void PF_precache_file (void)
1275 { // precache_file is only used to copy files with qcc, it does nothing
1276 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1279 void PF_precache_sound (void)
1284 if (sv.state != ss_loading)
1285 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1287 s = G_STRING(OFS_PARM0);
1288 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1289 PR_CheckEmptyString (s);
1291 for (i=0 ; i<MAX_SOUNDS ; i++)
1293 if (!sv.sound_precache[i])
1295 sv.sound_precache[i] = s;
1298 if (!strcmp(sv.sound_precache[i], s))
1301 Host_Error ("PF_precache_sound: overflow");
1304 void PF_precache_model (void)
1309 if (sv.state != ss_loading)
1310 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1312 s = G_STRING(OFS_PARM0);
1313 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1315 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1316 PR_CheckEmptyString (s);
1318 for (i=0 ; i<MAX_MODELS ; i++)
1320 if (!sv.model_precache[i])
1322 sv.model_precache[i] = s;
1323 sv.models[i] = Mod_ForName (s, true, false, false);
1326 if (!strcmp(sv.model_precache[i], s))
1329 Host_Error ("PF_precache_model: overflow");
1333 void PF_coredump (void)
1338 void PF_traceon (void)
1343 void PF_traceoff (void)
1348 void PF_eprint (void)
1350 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1357 float(float yaw, float dist) walkmove
1360 void PF_walkmove (void)
1368 ent = PROG_TO_EDICT(pr_global_struct->self);
1369 yaw = G_FLOAT(OFS_PARM0);
1370 dist = G_FLOAT(OFS_PARM1);
1372 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1374 G_FLOAT(OFS_RETURN) = 0;
1378 yaw = yaw*M_PI*2 / 360;
1380 move[0] = cos(yaw)*dist;
1381 move[1] = sin(yaw)*dist;
1384 // save program state, because SV_movestep may call other progs
1385 oldf = pr_xfunction;
1386 oldself = pr_global_struct->self;
1388 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1391 // restore program state
1392 pr_xfunction = oldf;
1393 pr_global_struct->self = oldself;
1403 void PF_droptofloor (void)
1409 ent = PROG_TO_EDICT(pr_global_struct->self);
1411 VectorCopy (ent->v->origin, end);
1414 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1416 if (trace.fraction == 1)
1417 G_FLOAT(OFS_RETURN) = 0;
1420 VectorCopy (trace.endpos, ent->v->origin);
1421 SV_LinkEdict (ent, false);
1422 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1423 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1424 G_FLOAT(OFS_RETURN) = 1;
1425 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1426 ent->e->suspendedinairflag = true;
1434 void(float style, string value) lightstyle
1437 void PF_lightstyle (void)
1444 style = G_FLOAT(OFS_PARM0);
1445 val = G_STRING(OFS_PARM1);
1447 // change the string in sv
1448 sv.lightstyles[style] = val;
1450 // send message to all clients on this server
1451 if (sv.state != ss_active)
1454 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1455 if (client->active || client->spawned)
1457 MSG_WriteChar (&client->message, svc_lightstyle);
1458 MSG_WriteChar (&client->message,style);
1459 MSG_WriteString (&client->message, val);
1466 f = G_FLOAT(OFS_PARM0);
1468 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1470 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1472 void PF_floor (void)
1474 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1478 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1487 void PF_checkbottom (void)
1489 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1497 void PF_pointcontents (void)
1499 G_FLOAT(OFS_RETURN) = sv.worldmodel->PointContents(sv.worldmodel, G_VECTOR(OFS_PARM0));
1506 entity nextent(entity)
1509 void PF_nextent (void)
1514 i = G_EDICTNUM(OFS_PARM0);
1517 pr_xfunction->builtinsprofile++;
1519 if (i == sv.num_edicts)
1521 RETURN_EDICT(sv.edicts);
1537 Pick a vector for the player to shoot along
1538 vector aim(entity, missilespeed)
1543 edict_t *ent, *check, *bestent;
1544 vec3_t start, dir, end, bestdir;
1547 float dist, bestdist;
1550 ent = G_EDICT(OFS_PARM0);
1551 speed = G_FLOAT(OFS_PARM1);
1553 VectorCopy (ent->v->origin, start);
1556 // try sending a trace straight
1557 VectorCopy (pr_global_struct->v_forward, dir);
1558 VectorMA (start, 2048, dir, end);
1559 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1560 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1561 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1563 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1568 // try all possible entities
1569 VectorCopy (dir, bestdir);
1570 bestdist = sv_aim.value;
1573 check = NEXT_EDICT(sv.edicts);
1574 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1576 pr_xfunction->builtinsprofile++;
1577 if (check->v->takedamage != DAMAGE_AIM)
1581 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1582 continue; // don't aim at teammate
1583 for (j=0 ; j<3 ; j++)
1584 end[j] = check->v->origin[j]
1585 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1586 VectorSubtract (end, start, dir);
1587 VectorNormalize (dir);
1588 dist = DotProduct (dir, pr_global_struct->v_forward);
1589 if (dist < bestdist)
1590 continue; // to far to turn
1591 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1592 if (tr.ent == check)
1593 { // can shoot at this one
1601 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1602 dist = DotProduct (dir, pr_global_struct->v_forward);
1603 VectorScale (pr_global_struct->v_forward, dist, end);
1605 VectorNormalize (end);
1606 VectorCopy (end, G_VECTOR(OFS_RETURN));
1610 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1618 This was a major timewaster in progs, so it was converted to C
1621 void PF_changeyaw (void)
1624 float ideal, current, move, speed;
1626 ent = PROG_TO_EDICT(pr_global_struct->self);
1627 current = ANGLEMOD(ent->v->angles[1]);
1628 ideal = ent->v->ideal_yaw;
1629 speed = ent->v->yaw_speed;
1631 if (current == ideal)
1633 move = ideal - current;
1634 if (ideal > current)
1655 ent->v->angles[1] = ANGLEMOD (current + move);
1663 void PF_changepitch (void)
1666 float ideal, current, move, speed;
1669 ent = G_EDICT(OFS_PARM0);
1670 current = ANGLEMOD( ent->v->angles[0] );
1671 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1672 ideal = val->_float;
1675 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1678 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1679 speed = val->_float;
1682 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1686 if (current == ideal)
1688 move = ideal - current;
1689 if (ideal > current)
1710 ent->v->angles[0] = ANGLEMOD (current + move);
1714 ===============================================================================
1718 ===============================================================================
1721 #define MSG_BROADCAST 0 // unreliable to all
1722 #define MSG_ONE 1 // reliable to one (msg_entity)
1723 #define MSG_ALL 2 // reliable to all
1724 #define MSG_INIT 3 // write to the init string
1726 sizebuf_t *WriteDest (void)
1732 dest = G_FLOAT(OFS_PARM0);
1736 return &sv.datagram;
1739 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1740 entnum = NUM_FOR_EDICT(ent);
1741 if (entnum < 1 || entnum > svs.maxclients)
1742 Host_Error ("WriteDest: not a client");
1743 return &svs.clients[entnum-1].message;
1746 return &sv.reliable_datagram;
1752 Host_Error ("WriteDest: bad destination");
1759 void PF_WriteByte (void)
1761 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1764 void PF_WriteChar (void)
1766 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1769 void PF_WriteShort (void)
1771 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1774 void PF_WriteLong (void)
1776 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1779 void PF_WriteAngle (void)
1781 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1784 void PF_WriteCoord (void)
1786 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1789 void PF_WriteString (void)
1791 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1795 void PF_WriteEntity (void)
1797 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1800 //=============================================================================
1802 void PF_makestatic (void)
1807 ent = G_EDICT(OFS_PARM0);
1810 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1815 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1816 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1817 MSG_WriteShort (&sv.signon, ent->v->frame);
1821 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1822 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1823 MSG_WriteByte (&sv.signon, ent->v->frame);
1826 MSG_WriteByte (&sv.signon, ent->v->colormap);
1827 MSG_WriteByte (&sv.signon, ent->v->skin);
1828 for (i=0 ; i<3 ; i++)
1830 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1831 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1834 // throw the entity away now
1838 //=============================================================================
1845 void PF_setspawnparms (void)
1851 ent = G_EDICT(OFS_PARM0);
1852 i = NUM_FOR_EDICT(ent);
1853 if (i < 1 || i > svs.maxclients)
1854 Host_Error ("Entity is not a client");
1856 // copy spawn parms out of the client_t
1857 client = svs.clients + (i-1);
1859 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1860 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1868 void PF_changelevel (void)
1872 // make sure we don't issue two changelevels
1873 if (svs.changelevel_issued)
1875 svs.changelevel_issued = true;
1877 s = G_STRING(OFS_PARM0);
1878 Cbuf_AddText (va("changelevel %s\n",s));
1883 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1888 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1893 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1900 Returns a vector of length < 1
1905 void PF_randomvec (void)
1910 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1911 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1912 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1914 while (DotProduct(temp, temp) >= 1);
1915 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1918 void SV_LightPoint (vec3_t color, vec3_t p);
1923 Returns a color vector indicating the lighting at the requested point.
1925 (Internal Operation note: actually measures the light beneath the point, just like
1926 the model lighting on the client)
1931 void PF_GetLight (void)
1935 p = G_VECTOR(OFS_PARM0);
1936 SV_LightPoint (color, p);
1937 VectorCopy (color, G_VECTOR(OFS_RETURN));
1940 #define MAX_QC_CVARS 128
1941 cvar_t qc_cvar[MAX_QC_CVARS];
1944 void PF_registercvar (void)
1948 name = G_STRING(OFS_PARM0);
1949 value = G_STRING(OFS_PARM1);
1950 G_FLOAT(OFS_RETURN) = 0;
1951 // first check to see if it has already been defined
1952 if (Cvar_FindVar (name))
1955 // check for overlap with a command
1956 if (Cmd_Exists (name))
1958 Con_Printf ("PF_registercvar: %s is a command\n", name);
1962 if (currentqc_cvar >= MAX_QC_CVARS)
1963 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1965 // copy the name and value
1966 variable = &qc_cvar[currentqc_cvar++];
1967 variable->name = Z_Malloc (strlen(name)+1);
1968 strcpy (variable->name, name);
1969 variable->string = Z_Malloc (strlen(value)+1);
1970 strcpy (variable->string, value);
1971 variable->value = atof (value);
1973 Cvar_RegisterVariable(variable);
1974 G_FLOAT(OFS_RETURN) = 1; // success
1981 returns the minimum of two supplied floats
1988 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1990 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1991 else if (pr_argc >= 3)
1994 float f = G_FLOAT(OFS_PARM0);
1995 for (i = 1;i < pr_argc;i++)
1996 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1997 f = G_FLOAT((OFS_PARM0+i*3));
1998 G_FLOAT(OFS_RETURN) = f;
2001 Host_Error("min: must supply at least 2 floats\n");
2008 returns the maximum of two supplied floats
2015 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2017 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2018 else if (pr_argc >= 3)
2021 float f = G_FLOAT(OFS_PARM0);
2022 for (i = 1;i < pr_argc;i++)
2023 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2024 f = G_FLOAT((OFS_PARM0+i*3));
2025 G_FLOAT(OFS_RETURN) = f;
2028 Host_Error("max: must supply at least 2 floats\n");
2035 returns number bounded by supplied range
2037 min(min, value, max)
2040 void PF_bound (void)
2042 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2049 returns a raised to power b
2056 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2063 copies data from one entity to another
2065 copyentity(src, dst)
2068 void PF_copyentity (void)
2071 in = G_EDICT(OFS_PARM0);
2072 out = G_EDICT(OFS_PARM1);
2073 memcpy(out->v, in->v, progs->entityfields * 4);
2080 sets the color of a client and broadcasts the update to all connected clients
2082 setcolor(clientent, value)
2085 void PF_setcolor (void)
2091 entnum = G_EDICTNUM(OFS_PARM0);
2092 i = G_FLOAT(OFS_PARM1);
2094 if (entnum < 1 || entnum > svs.maxclients)
2096 Con_Printf ("tried to setcolor a non-client\n");
2100 client = &svs.clients[entnum-1];
2101 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2104 client->old_colors = i;
2105 client->edict->v->team = (i & 15) + 1;
2107 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2108 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2109 MSG_WriteByte (&sv.reliable_datagram, i);
2116 effect(origin, modelname, startframe, framecount, framerate)
2119 void PF_effect (void)
2122 s = G_STRING(OFS_PARM1);
2124 Host_Error("effect: no model specified\n");
2126 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2129 void PF_te_blood (void)
2131 if (G_FLOAT(OFS_PARM2) < 1)
2133 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2134 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2136 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2137 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2138 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2140 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2141 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2142 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2144 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2147 void PF_te_bloodshower (void)
2149 if (G_FLOAT(OFS_PARM3) < 1)
2151 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2152 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2154 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2155 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2156 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2158 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2159 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2160 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2162 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2164 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2167 void PF_te_explosionrgb (void)
2169 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2170 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2172 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2173 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2174 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2176 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2177 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2178 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2181 void PF_te_particlecube (void)
2183 if (G_FLOAT(OFS_PARM3) < 1)
2185 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2186 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2189 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2190 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2192 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2193 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2194 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2196 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2197 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2198 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2200 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2202 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2203 // gravity true/false
2204 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2206 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2209 void PF_te_particlerain (void)
2211 if (G_FLOAT(OFS_PARM3) < 1)
2213 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2214 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2217 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2218 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2220 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2221 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2222 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2224 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2225 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2226 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2228 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2230 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2233 void PF_te_particlesnow (void)
2235 if (G_FLOAT(OFS_PARM3) < 1)
2237 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2238 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2241 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2242 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2244 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2245 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2246 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2248 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2249 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2250 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2252 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2254 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2257 void PF_te_spark (void)
2259 if (G_FLOAT(OFS_PARM2) < 1)
2261 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2262 MSG_WriteByte(&sv.datagram, TE_SPARK);
2264 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2266 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2268 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2269 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2270 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2272 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2275 void PF_te_gunshotquad (void)
2277 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2280 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2285 void PF_te_spikequad (void)
2287 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2288 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2290 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2292 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2295 void PF_te_superspikequad (void)
2297 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2298 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2300 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2301 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2302 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2305 void PF_te_explosionquad (void)
2307 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2308 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2310 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2312 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2315 void PF_te_smallflash (void)
2317 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2318 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2320 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2321 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2322 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2325 void PF_te_customflash (void)
2327 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2329 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2330 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2332 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2333 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2334 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2336 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2338 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2340 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2341 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2342 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2345 void PF_te_gunshot (void)
2347 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2350 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2355 void PF_te_spike (void)
2357 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2358 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2360 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2365 void PF_te_superspike (void)
2367 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2368 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2370 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2375 void PF_te_explosion (void)
2377 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2378 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2380 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2381 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2382 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2385 void PF_te_tarexplosion (void)
2387 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2388 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2390 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2392 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2395 void PF_te_wizspike (void)
2397 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2398 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2400 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2402 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2405 void PF_te_knightspike (void)
2407 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2408 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2410 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2415 void PF_te_lavasplash (void)
2417 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2420 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2425 void PF_te_teleport (void)
2427 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2428 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2430 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2435 void PF_te_explosion2 (void)
2437 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2438 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2440 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2441 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2442 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2444 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2447 void PF_te_lightning1 (void)
2449 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2450 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2452 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2454 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2455 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2456 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2458 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2463 void PF_te_lightning2 (void)
2465 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2466 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2468 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2470 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2472 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2474 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2479 void PF_te_lightning3 (void)
2481 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2482 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2484 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2486 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2487 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2488 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2490 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2495 void PF_te_beam (void)
2497 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2498 MSG_WriteByte(&sv.datagram, TE_BEAM);
2500 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2502 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2503 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2504 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2506 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2507 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2508 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2511 void PF_te_plasmaburn (void)
2513 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2514 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2515 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2516 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2517 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2520 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2523 vec3_t v1, clipplanenormal, normal;
2524 vec_t clipplanedist, clipdist;
2526 if (surf->flags & SURF_PLANEBACK)
2527 VectorNegate(surf->plane->normal, normal);
2529 VectorCopy(surf->plane->normal, normal);
2530 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2532 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2533 VectorNormalizeFast(v1);
2534 CrossProduct(v1, normal, clipplanenormal);
2535 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2536 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2539 clipdist = -clipdist;
2540 VectorMA(out, clipdist, clipplanenormal, out);
2545 static msurface_t *getsurface(edict_t *ed, int surfnum)
2549 if (!ed || ed->e->free)
2551 modelindex = ed->v->modelindex;
2552 if (modelindex < 1 || modelindex >= MAX_MODELS)
2554 model = sv.models[modelindex];
2555 if (model->type != mod_brush)
2557 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2559 return model->surfaces + surfnum + model->firstmodelsurface;
2563 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2564 void PF_getsurfacenumpoints(void)
2567 // return 0 if no such surface
2568 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2570 G_FLOAT(OFS_RETURN) = 0;
2574 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2576 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2577 void PF_getsurfacepoint(void)
2582 VectorClear(G_VECTOR(OFS_RETURN));
2583 ed = G_EDICT(OFS_PARM0);
2584 if (!ed || ed->e->free)
2586 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2588 pointnum = G_FLOAT(OFS_PARM2);
2589 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2591 // FIXME: implement rotation/scaling
2592 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2594 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2595 void PF_getsurfacenormal(void)
2598 VectorClear(G_VECTOR(OFS_RETURN));
2599 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2601 // FIXME: implement rotation/scaling
2602 if (surf->flags & SURF_PLANEBACK)
2603 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2605 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2607 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2608 void PF_getsurfacetexture(void)
2611 G_INT(OFS_RETURN) = 0;
2612 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2614 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2616 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2617 void PF_getsurfacenearpoint(void)
2619 int surfnum, best, modelindex;
2621 vec_t dist, bestdist;
2626 G_FLOAT(OFS_RETURN) = -1;
2627 ed = G_EDICT(OFS_PARM0);
2628 point = G_VECTOR(OFS_PARM1);
2630 if (!ed || ed->e->free)
2632 modelindex = ed->v->modelindex;
2633 if (modelindex < 1 || modelindex >= MAX_MODELS)
2635 model = sv.models[modelindex];
2636 if (model->type != mod_brush)
2639 // FIXME: implement rotation/scaling
2640 VectorSubtract(point, ed->v->origin, p);
2642 bestdist = 1000000000;
2643 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2645 surf = model->surfaces + surfnum + model->firstmodelsurface;
2646 dist = PlaneDiff(p, surf->plane);
2648 if (dist < bestdist)
2650 clippointtosurface(surf, p, clipped);
2651 VectorSubtract(clipped, p, clipped);
2652 dist += DotProduct(clipped, clipped);
2653 if (dist < bestdist)
2660 G_FLOAT(OFS_RETURN) = best;
2662 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2663 void PF_getsurfaceclippedpoint(void)
2668 VectorClear(G_VECTOR(OFS_RETURN));
2669 ed = G_EDICT(OFS_PARM0);
2670 if (!ed || ed->e->free)
2672 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2674 // FIXME: implement rotation/scaling
2675 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2676 clippointtosurface(surf, p, out);
2677 // FIXME: implement rotation/scaling
2678 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2681 #define MAX_PRFILES 256
2683 qfile_t *pr_files[MAX_PRFILES];
2685 void PR_Files_Init(void)
2687 memset(pr_files, 0, sizeof(pr_files));
2690 void PR_Files_CloseAll(void)
2693 for (i = 0;i < MAX_PRFILES;i++)
2696 FS_Close(pr_files[i]);
2701 //float(string s) stof = #81; // get numerical value from a string
2704 char *s = PF_VarString(0);
2705 G_FLOAT(OFS_RETURN) = atof(s);
2708 //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
2712 char *modestring, *filename;
2713 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2714 if (pr_files[filenum] == NULL)
2716 if (filenum >= MAX_PRFILES)
2718 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2719 G_FLOAT(OFS_RETURN) = -2;
2722 mode = G_FLOAT(OFS_PARM1);
2725 case 0: // FILE_READ
2728 case 1: // FILE_APPEND
2731 case 2: // FILE_WRITE
2735 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2736 G_FLOAT(OFS_RETURN) = -3;
2739 filename = G_STRING(OFS_PARM0);
2740 // .. is parent directory on many platforms
2741 // / is parent directory on Amiga
2742 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2743 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2744 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2746 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2747 G_FLOAT(OFS_RETURN) = -4;
2750 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2751 if (pr_files[filenum] == NULL)
2752 G_FLOAT(OFS_RETURN) = -1;
2754 G_FLOAT(OFS_RETURN) = filenum;
2757 //void(float fhandle) fclose = #111; // closes a file
2758 void PF_fclose(void)
2760 int filenum = G_FLOAT(OFS_PARM0);
2761 if (filenum < 0 || filenum >= MAX_PRFILES)
2763 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2766 if (pr_files[filenum] == NULL)
2768 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2771 FS_Close(pr_files[filenum]);
2772 pr_files[filenum] = NULL;
2775 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2779 static char string[MAX_VARSTRING];
2780 int filenum = G_FLOAT(OFS_PARM0);
2781 if (filenum < 0 || filenum >= MAX_PRFILES)
2783 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2786 if (pr_files[filenum] == NULL)
2788 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2794 c = FS_Getc(pr_files[filenum]);
2795 if (c == '\r' || c == '\n' || c < 0)
2797 if (end < MAX_VARSTRING - 1)
2801 // remove \n following \r
2803 c = FS_Getc(pr_files[filenum]);
2804 if (developer.integer)
2805 Con_Printf("fgets: %s\n", string);
2807 G_INT(OFS_RETURN) = PR_SetString(string);
2809 G_INT(OFS_RETURN) = 0;
2812 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2816 char *s = PF_VarString(1);
2817 int filenum = G_FLOAT(OFS_PARM0);
2818 if (filenum < 0 || filenum >= MAX_PRFILES)
2820 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2823 if (pr_files[filenum] == NULL)
2825 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2828 if ((stringlength = strlen(s)))
2829 FS_Write(pr_files[filenum], s, stringlength);
2830 if (developer.integer)
2831 Con_Printf("fputs: %s\n", s);
2834 //float(string s) strlen = #114; // returns how many characters are in a string
2835 void PF_strlen(void)
2838 s = G_STRING(OFS_PARM0);
2840 G_FLOAT(OFS_RETURN) = strlen(s);
2842 G_FLOAT(OFS_RETURN) = 0;
2845 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2846 void PF_strcat(void)
2848 char *s = PF_VarString(0);
2849 G_INT(OFS_RETURN) = PR_SetString(s);
2852 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2853 void PF_substring(void)
2856 char *s, string[MAX_VARSTRING];
2857 s = G_STRING(OFS_PARM0);
2858 start = G_FLOAT(OFS_PARM1);
2859 end = G_FLOAT(OFS_PARM2) + start;
2862 for (i = 0;i < start && *s;i++, s++);
2863 for (i = 0;i < MAX_VARSTRING - 1 && *s && i < end;i++, s++)
2866 G_INT(OFS_RETURN) = PR_SetString(string);
2869 //vector(string s) stov = #117; // returns vector value from a string
2872 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2875 //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)
2876 void PF_strzone(void)
2879 in = G_STRING(OFS_PARM0);
2880 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2882 G_INT(OFS_RETURN) = PR_SetString(out);
2885 //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!!!)
2886 void PF_strunzone(void)
2888 Mem_Free(G_STRING(OFS_PARM0));
2891 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2892 //this function originally written by KrimZon, made shorter by LordHavoc
2893 void PF_clientcommand (void)
2895 client_t *temp_client;
2898 //find client for this entity
2899 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2900 if (i < 0 || i >= svs.maxclients)
2901 Host_Error("PF_clientcommand: entity is not a client");
2903 temp_client = host_client;
2904 host_client = &svs.clients[i];
2905 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2906 host_client = temp_client;
2909 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2910 //this function originally written by KrimZon, made shorter by LordHavoc
2911 char **tokens = NULL;
2912 int max_tokens, num_tokens = 0;
2913 void PF_tokenize (void)
2917 str = G_STRING(OFS_PARM0);
2922 for (i=0;i<num_tokens;i++)
2928 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2929 max_tokens = strlen(str);
2931 for (p = str;COM_ParseToken(&p) && num_tokens < max_tokens;num_tokens++)
2933 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2934 strcpy(tokens[num_tokens], com_token);
2937 G_FLOAT(OFS_RETURN) = num_tokens;
2940 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2941 //this function originally written by KrimZon, made shorter by LordHavoc
2944 int token_num = G_FLOAT(OFS_PARM0);
2945 if (token_num >= 0 && token_num < num_tokens)
2946 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2948 G_INT(OFS_RETURN) = PR_SetString("");
2952 builtin_t pr_builtin[] =
2955 PF_makevectors, // #1 void(entity e) makevectors
2956 PF_setorigin, // #2 void(entity e, vector o) setorigin
2957 PF_setmodel, // #3 void(entity e, string m) setmodel
2958 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2959 NULL, // #5 void(entity e, vector min, vector max) setabssize
2960 PF_break, // #6 void() break
2961 PF_random, // #7 float() random
2962 PF_sound, // #8 void(entity e, float chan, string samp) sound
2963 PF_normalize, // #9 vector(vector v) normalize
2964 PF_error, // #10 void(string e) error
2965 PF_objerror, // #11 void(string e) objerror
2966 PF_vlen, // #12 float(vector v) vlen
2967 PF_vectoyaw, // #13 float(vector v) vectoyaw
2968 PF_Spawn, // #14 entity() spawn
2969 PF_Remove, // #15 void(entity e) remove
2970 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2971 PF_checkclient, // #17 entity() clientlist
2972 PF_Find, // #18 entity(entity start, .string fld, string match) find
2973 PF_precache_sound, // #19 void(string s) precache_sound
2974 PF_precache_model, // #20 void(string s) precache_model
2975 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2976 PF_findradius, // #22 entity(vector org, float rad) findradius
2977 PF_bprint, // #23 void(string s) bprint
2978 PF_sprint, // #24 void(entity client, string s) sprint
2979 PF_dprint, // #25 void(string s) dprint
2980 PF_ftos, // #26 void(string s) ftos
2981 PF_vtos, // #27 void(string s) vtos
2982 PF_coredump, // #28 void() coredump
2983 PF_traceon, // #29 void() traceon
2984 PF_traceoff, // #30 void() traceoff
2985 PF_eprint, // #31 void(entity e) eprint
2986 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2988 PF_droptofloor, // #34 float() droptofloor
2989 PF_lightstyle, // #35 void(float style, string value) lightstyle
2990 PF_rint, // #36 float(float v) rint
2991 PF_floor, // #37 float(float v) floor
2992 PF_ceil, // #38 float(float v) ceil
2994 PF_checkbottom, // #40 float(entity e) checkbottom
2995 PF_pointcontents , // #41 float(vector v) pointcontents
2997 PF_fabs, // #43 float(float f) fabs
2998 PF_aim, // #44 vector(entity e, float speed) aim
2999 PF_cvar, // #45 float(string s) cvar
3000 PF_localcmd, // #46 void(string s) localcmd
3001 PF_nextent, // #47 entity(entity e) nextent
3002 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3003 PF_changeyaw, // #49 void() ChangeYaw
3005 PF_vectoangles, // #51 vector(vector v) vectoangles
3006 PF_WriteByte, // #52 void(float to, float f) WriteByte
3007 PF_WriteChar, // #53 void(float to, float f) WriteChar
3008 PF_WriteShort, // #54 void(float to, float f) WriteShort
3009 PF_WriteLong, // #55 void(float to, float f) WriteLong
3010 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3011 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3012 PF_WriteString, // #58 void(float to, string s) WriteString
3013 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3014 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3015 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3016 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3017 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3018 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3019 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3021 SV_MoveToGoal, // #67 void(float step) movetogoal
3022 PF_precache_file, // #68 string(string s) precache_file
3023 PF_makestatic, // #69 void(entity e) makestatic
3024 PF_changelevel, // #70 void(string s) changelevel
3026 PF_cvar_set, // #72 void(string var, string val) cvar_set
3027 PF_centerprint, // #73 void(entity client, strings) centerprint
3028 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3029 PF_precache_model, // #75 string(string s) precache_model2
3030 PF_precache_sound, // #76 string(string s) precache_sound2
3031 PF_precache_file, // #77 string(string s) precache_file2
3032 PF_setspawnparms, // #78 void(entity e) setspawnparms
3035 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3044 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3045 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3046 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3047 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3048 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3049 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3050 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3051 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3052 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3053 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3064 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3065 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3066 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3067 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3068 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3069 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3070 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3071 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3072 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3073 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3074 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3075 a a a a a a a a // #120-199
3076 a a a a a a a a a a // #200-299
3077 a a a a a a a a a a // #300-399
3078 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3079 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3080 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3081 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3082 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3083 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3084 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3085 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3086 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3087 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3088 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3089 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3090 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3091 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3092 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3093 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3094 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3095 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3096 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3097 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3098 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3099 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3100 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3101 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3102 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3103 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3104 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3105 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3106 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3107 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3108 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3109 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3110 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3111 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3112 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3113 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3114 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3115 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3116 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3117 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3118 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3119 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3120 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3128 a a a a a // #450-499 (LordHavoc)
3131 builtin_t *pr_builtins = pr_builtin;
3132 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3134 void PR_Cmd_Init(void)
3136 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3140 void PR_Cmd_Reset(void)
3142 Mem_EmptyPool(pr_strings_mempool);
3143 PR_Files_CloseAll();