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 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
34 static char *PR_GetTempString(void)
37 s = pr_string_temp[pr_string_tempindex];
38 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
42 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
46 ===============================================================================
50 ===============================================================================
54 void PF_VarString(int first, char *out, int outlength)
60 outend = out + outlength - 1;
61 for (i = first;i < pr_argc && out < outend;i++)
63 s = G_STRING((OFS_PARM0+i*3));
64 while (out < outend && *s)
70 char *ENGINE_EXTENSIONS =
80 "DP_ENT_CUSTOMCOLORMAP "
81 "DP_ENT_EXTERIORMODELTOCLIENT "
82 "DP_ENT_LOWPRECISION "
86 "DP_GFX_EXTERNALTEXTURES "
88 "DP_GFX_QUAKE3MODELTAGS "
92 "DP_HALFLIFE_MAP_CVAR "
96 "DP_MOVETYPEBOUNCEMISSILE "
102 "DP_QC_FINDCHAINFLOAT "
108 "DP_QC_SINCOSSQRTPOW "
111 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
112 "DP_QC_TRACE_MOVETYPE_HITMODEL "
113 "DP_QC_VECTORVECTORS "
119 "DP_SV_DRAWONLYTOCLIENT "
121 "DP_SV_EXTERIORMODELTOCLIENT "
122 "DP_SV_NODRAWTOCLIENT "
123 "DP_SV_PLAYERPHYSICS "
129 "DP_TE_EXPLOSIONRGB "
131 "DP_TE_PARTICLECUBE "
132 "DP_TE_PARTICLERAIN "
133 "DP_TE_PARTICLESNOW "
135 "DP_TE_QUADEFFECTS1 "
138 "DP_TE_STANDARDEFFECTBUILTINS "
141 "KRIMZON_SV_PARSECLIENTCOMMAND "
147 qboolean checkextension(char *name)
152 for (e = ENGINE_EXTENSIONS;*e;e++)
159 while (*e && *e != ' ')
161 if (e - start == len)
162 if (!strncasecmp(start, name, len))
172 returns true if the extension is supported by the server
174 checkextension(extensionname)
177 void PF_checkextension (void)
179 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
186 This is a TERMINAL error, which will kill off the entire server.
195 char string[STRINGTEMP_LENGTH];
197 PF_VarString(0, string, sizeof(string));
198 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
199 ed = PROG_TO_EDICT(pr_global_struct->self);
202 Host_Error ("Program error");
209 Dumps out self, then an error message. The program is aborted and self is
210 removed, but the level can continue.
215 void PF_objerror (void)
218 char string[STRINGTEMP_LENGTH];
220 PF_VarString(0, string, sizeof(string));
221 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
222 ed = PROG_TO_EDICT(pr_global_struct->self);
232 Writes new values for v_forward, v_up, and v_right based on angles
236 void PF_makevectors (void)
238 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
245 Writes new values for v_forward, v_up, and v_right based on the given forward vector
246 vectorvectors(vector, vector)
249 void PF_vectorvectors (void)
251 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
252 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
259 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.
261 setorigin (entity, origin)
264 void PF_setorigin (void)
269 e = G_EDICT(OFS_PARM0);
271 Host_Error("setorigin: can not modify world entity\n");
273 Host_Error("setorigin: can not modify free entity\n");
274 org = G_VECTOR(OFS_PARM1);
275 VectorCopy (org, e->v->origin);
276 SV_LinkEdict (e, false);
280 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
284 for (i=0 ; i<3 ; i++)
286 Host_Error ("backwards mins/maxs");
288 // set derived values
289 VectorCopy (min, e->v->mins);
290 VectorCopy (max, e->v->maxs);
291 VectorSubtract (max, min, e->v->size);
293 SV_LinkEdict (e, false);
300 the size box is rotated by the current angle
301 LordHavoc: no it isn't...
303 setsize (entity, minvector, maxvector)
306 void PF_setsize (void)
311 e = G_EDICT(OFS_PARM0);
313 Host_Error("setsize: can not modify world entity\n");
315 Host_Error("setsize: can not modify free entity\n");
316 min = G_VECTOR(OFS_PARM1);
317 max = G_VECTOR(OFS_PARM2);
318 SetMinMaxSize (e, min, max, false);
326 setmodel(entity, model)
329 void PF_setmodel (void)
336 e = G_EDICT(OFS_PARM0);
338 Host_Error("setmodel: can not modify world entity\n");
340 Host_Error("setmodel: can not modify free entity\n");
341 m = G_STRING(OFS_PARM1);
343 // check to see if model was properly precached
344 for (i=0, check = sv.model_precache ; *check ; i++, check++)
345 if (!strcmp(*check, m))
349 Host_Error ("no precache: %s\n", m);
352 e->v->model = PR_SetString(*check);
353 e->v->modelindex = i;
355 mod = sv.models[ (int)e->v->modelindex];
358 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
360 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
367 broadcast print to everyone on server
372 void PF_bprint (void)
374 char string[STRINGTEMP_LENGTH];
375 PF_VarString(0, string, sizeof(string));
376 SV_BroadcastPrintf("%s", string);
383 single print to a specific client
385 sprint(clientent, value)
388 void PF_sprint (void)
392 char string[STRINGTEMP_LENGTH];
394 entnum = G_EDICTNUM(OFS_PARM0);
396 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
398 Con_Printf ("tried to sprint to a non-client\n");
402 client = svs.clients + entnum-1;
403 if (!client->netconnection)
405 PF_VarString(1, string, sizeof(string));
406 MSG_WriteChar(&client->message,svc_print);
407 MSG_WriteString(&client->message, string);
415 single print to a specific client
417 centerprint(clientent, value)
420 void PF_centerprint (void)
424 char string[STRINGTEMP_LENGTH];
426 entnum = G_EDICTNUM(OFS_PARM0);
428 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
430 Con_Printf ("tried to sprint to a non-client\n");
434 client = svs.clients + entnum-1;
435 if (!client->netconnection)
437 PF_VarString(1, string, sizeof(string));
438 MSG_WriteChar(&client->message,svc_centerprint);
439 MSG_WriteString(&client->message, string);
447 vector normalize(vector)
450 void PF_normalize (void)
456 value1 = G_VECTOR(OFS_PARM0);
458 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
462 newvalue[0] = newvalue[1] = newvalue[2] = 0;
466 newvalue[0] = value1[0] * new;
467 newvalue[1] = value1[1] * new;
468 newvalue[2] = value1[2] * new;
471 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
486 value1 = G_VECTOR(OFS_PARM0);
488 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
491 G_FLOAT(OFS_RETURN) = new;
498 float vectoyaw(vector)
501 void PF_vectoyaw (void)
506 value1 = G_VECTOR(OFS_PARM0);
508 if (value1[1] == 0 && value1[0] == 0)
512 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
517 G_FLOAT(OFS_RETURN) = yaw;
525 vector vectoangles(vector)
528 void PF_vectoangles (void)
534 value1 = G_VECTOR(OFS_PARM0);
536 if (value1[1] == 0 && value1[0] == 0)
546 // LordHavoc: optimized a bit
549 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
553 else if (value1[1] > 0)
558 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
559 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
564 G_FLOAT(OFS_RETURN+0) = pitch;
565 G_FLOAT(OFS_RETURN+1) = yaw;
566 G_FLOAT(OFS_RETURN+2) = 0;
573 Returns a number from 0<= num < 1
578 void PF_random (void)
582 num = (rand ()&0x7fff) / ((float)0x7fff);
584 G_FLOAT(OFS_RETURN) = num;
591 particle(origin, color, count)
594 void PF_particle (void)
600 org = G_VECTOR(OFS_PARM0);
601 dir = G_VECTOR(OFS_PARM1);
602 color = G_FLOAT(OFS_PARM2);
603 count = G_FLOAT(OFS_PARM3);
604 SV_StartParticle (org, dir, color, count);
614 void PF_ambientsound (void)
619 float vol, attenuation;
620 int i, soundnum, large;
622 pos = G_VECTOR (OFS_PARM0);
623 samp = G_STRING(OFS_PARM1);
624 vol = G_FLOAT(OFS_PARM2);
625 attenuation = G_FLOAT(OFS_PARM3);
627 // check to see if samp was properly precached
628 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
629 if (!strcmp(*check,samp))
634 Con_Printf ("no precache: %s\n", samp);
642 // add an svc_spawnambient command to the level signon packet
645 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
647 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
649 for (i=0 ; i<3 ; i++)
650 MSG_WriteDPCoord(&sv.signon, pos[i]);
653 MSG_WriteShort (&sv.signon, soundnum);
655 MSG_WriteByte (&sv.signon, soundnum);
657 MSG_WriteByte (&sv.signon, vol*255);
658 MSG_WriteByte (&sv.signon, attenuation*64);
666 Each entity can have eight independant sound sources, like voice,
669 Channel 0 is an auto-allocate channel, the others override anything
670 already running on that entity/channel pair.
672 An attenuation of 0 will play full volume everywhere in the level.
673 Larger attenuations will drop off.
685 entity = G_EDICT(OFS_PARM0);
686 channel = G_FLOAT(OFS_PARM1);
687 sample = G_STRING(OFS_PARM2);
688 volume = G_FLOAT(OFS_PARM3) * 255;
689 attenuation = G_FLOAT(OFS_PARM4);
691 if (volume < 0 || volume > 255)
692 Host_Error ("SV_StartSound: volume = %i", volume);
694 if (attenuation < 0 || attenuation > 4)
695 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
697 if (channel < 0 || channel > 7)
698 Host_Error ("SV_StartSound: channel = %i", channel);
700 SV_StartSound (entity, channel, sample, volume, attenuation);
712 Host_Error ("break statement");
719 Used for use tracing and shot targeting
720 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
721 if the tryents flag is set.
723 traceline (vector1, vector2, tryents)
726 void PF_traceline (void)
733 pr_xfunction->builtinsprofile += 30;
735 v1 = G_VECTOR(OFS_PARM0);
736 v2 = G_VECTOR(OFS_PARM1);
737 nomonsters = G_FLOAT(OFS_PARM2);
738 ent = G_EDICT(OFS_PARM3);
740 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
742 pr_global_struct->trace_allsolid = trace.allsolid;
743 pr_global_struct->trace_startsolid = trace.startsolid;
744 pr_global_struct->trace_fraction = trace.fraction;
745 pr_global_struct->trace_inwater = trace.inwater;
746 pr_global_struct->trace_inopen = trace.inopen;
747 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
748 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
749 pr_global_struct->trace_plane_dist = trace.plane.dist;
751 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
753 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
754 // FIXME: add trace_endcontents
762 Used for use tracing and shot targeting
763 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
764 if the tryents flag is set.
766 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
769 // LordHavoc: added this for my own use, VERY useful, similar to traceline
770 void PF_tracebox (void)
772 float *v1, *v2, *m1, *m2;
777 pr_xfunction->builtinsprofile += 30;
779 v1 = G_VECTOR(OFS_PARM0);
780 m1 = G_VECTOR(OFS_PARM1);
781 m2 = G_VECTOR(OFS_PARM2);
782 v2 = G_VECTOR(OFS_PARM3);
783 nomonsters = G_FLOAT(OFS_PARM4);
784 ent = G_EDICT(OFS_PARM5);
786 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
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);
802 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
803 void PF_TraceToss (void)
809 pr_xfunction->builtinsprofile += 600;
811 ent = G_EDICT(OFS_PARM0);
812 if (ent == sv.edicts)
813 Host_Error("tracetoss: can not use world entity\n");
814 ignore = G_EDICT(OFS_PARM1);
816 trace = SV_Trace_Toss (ent, ignore);
818 pr_global_struct->trace_allsolid = trace.allsolid;
819 pr_global_struct->trace_startsolid = trace.startsolid;
820 pr_global_struct->trace_fraction = trace.fraction;
821 pr_global_struct->trace_inwater = trace.inwater;
822 pr_global_struct->trace_inopen = trace.inopen;
823 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
824 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
825 pr_global_struct->trace_plane_dist = trace.plane.dist;
827 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
829 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
837 Returns true if the given entity can move to the given position from it's
838 current position by walking or rolling.
840 scalar checkpos (entity, vector)
843 void PF_checkpos (void)
847 //============================================================================
850 qbyte checkpvs[MAX_MAP_LEAFS/8];
852 int PF_newcheckclient (int check)
858 // cycle to the next one
860 check = bound(1, check, svs.maxclients);
861 if (check == svs.maxclients)
869 pr_xfunction->builtinsprofile++;
871 if (i == svs.maxclients+1)
873 // look up the client's edict
875 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
876 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
878 // found a valid client (possibly the same one again)
882 // get the PVS for the entity
883 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
885 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
886 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
895 Returns a client (or object that has a client enemy) that would be a
898 If there is more than one valid option, they are cycled each frame
900 If (self.origin + self.viewofs) is not in the PVS of the current target,
901 it is not returned at all.
906 int c_invis, c_notvis;
907 void PF_checkclient (void)
912 // find a new check if on a new frame
913 if (sv.time - sv.lastchecktime >= 0.1)
915 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
916 sv.lastchecktime = sv.time;
919 // return check if it might be visible
920 ent = EDICT_NUM(sv.lastcheck);
921 if (ent->e->free || ent->v->health <= 0)
923 RETURN_EDICT(sv.edicts);
927 // if current entity can't possibly see the check entity, return 0
928 self = PROG_TO_EDICT(pr_global_struct->self);
929 VectorAdd(self->v->origin, self->v->view_ofs, view);
930 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
933 RETURN_EDICT(sv.edicts);
937 // might be able to see it
942 //============================================================================
949 Sends text over to the client's execution buffer
951 stuffcmd (clientent, value)
954 void PF_stuffcmd (void)
960 entnum = G_EDICTNUM(OFS_PARM0);
961 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
963 Con_Printf("Can't stuffcmd to a non-client");
966 str = G_STRING(OFS_PARM1);
969 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
970 Host_ClientCommands ("%s", str);
978 Sends text to server console
983 void PF_localcmd (void)
985 Cbuf_AddText(G_STRING(OFS_PARM0));
997 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1007 void PF_cvar_set (void)
1009 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1016 Returns a chain of entities that have origins within a spherical area
1018 findradius (origin, radius)
1021 void PF_findradius (void)
1023 edict_t *ent, *chain;
1030 chain = (edict_t *)sv.edicts;
1032 org = G_VECTOR(OFS_PARM0);
1033 radius = G_FLOAT(OFS_PARM1);
1034 radius2 = radius * radius;
1036 ent = NEXT_EDICT(sv.edicts);
1037 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1039 pr_xfunction->builtinsprofile++;
1042 if (ent->v->solid == SOLID_NOT)
1045 // LordHavoc: compare against bounding box rather than center,
1046 // and use DotProduct instead of Length, major speedup
1047 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1048 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1049 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1050 if (DotProduct(eorg, eorg) > radius2)
1053 ent->v->chain = EDICT_TO_PROG(chain);
1057 RETURN_EDICT(chain);
1066 void PF_dprint (void)
1068 char string[STRINGTEMP_LENGTH];
1069 if (developer.integer)
1071 PF_VarString(0, string, sizeof(string));
1072 Con_Printf("%s",string);
1080 v = G_FLOAT(OFS_PARM0);
1082 s = PR_GetTempString();
1083 if ((float)((int)v) == v)
1084 sprintf(s, "%i", (int)v);
1086 sprintf(s, "%f", 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");
1131 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1132 if (ed->e->free && developer.integer)
1133 Con_Printf("remove: tried to remove an entity that was already removed\n");
1138 // entity (entity start, .string field, string match) find = #5;
1146 e = G_EDICTNUM(OFS_PARM0);
1147 f = G_INT(OFS_PARM1);
1148 s = G_STRING(OFS_PARM2);
1151 RETURN_EDICT(sv.edicts);
1155 for (e++ ; e < sv.num_edicts ; e++)
1157 pr_xfunction->builtinsprofile++;
1171 RETURN_EDICT(sv.edicts);
1174 // LordHavoc: added this for searching float, int, and entity reference fields
1175 void PF_FindFloat (void)
1182 e = G_EDICTNUM(OFS_PARM0);
1183 f = G_INT(OFS_PARM1);
1184 s = G_FLOAT(OFS_PARM2);
1186 for (e++ ; e < sv.num_edicts ; e++)
1188 pr_xfunction->builtinsprofile++;
1192 if (E_FLOAT(ed,f) == s)
1199 RETURN_EDICT(sv.edicts);
1202 // chained search for strings in entity fields
1203 // entity(.string field, string match) findchain = #402;
1204 void PF_findchain (void)
1209 edict_t *ent, *chain;
1211 chain = (edict_t *)sv.edicts;
1213 f = G_INT(OFS_PARM0);
1214 s = G_STRING(OFS_PARM1);
1217 RETURN_EDICT(sv.edicts);
1221 ent = NEXT_EDICT(sv.edicts);
1222 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1224 pr_xfunction->builtinsprofile++;
1227 t = E_STRING(ent,f);
1233 ent->v->chain = EDICT_TO_PROG(chain);
1237 RETURN_EDICT(chain);
1240 // LordHavoc: chained search for float, int, and entity reference fields
1241 // entity(.string field, float match) findchainfloat = #403;
1242 void PF_findchainfloat (void)
1247 edict_t *ent, *chain;
1249 chain = (edict_t *)sv.edicts;
1251 f = G_INT(OFS_PARM0);
1252 s = G_FLOAT(OFS_PARM1);
1254 ent = NEXT_EDICT(sv.edicts);
1255 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1257 pr_xfunction->builtinsprofile++;
1260 if (E_FLOAT(ent,f) != s)
1263 ent->v->chain = EDICT_TO_PROG(chain);
1267 RETURN_EDICT(chain);
1270 void PR_CheckEmptyString (char *s)
1273 Host_Error ("Bad string");
1276 void PF_precache_file (void)
1277 { // precache_file is only used to copy files with qcc, it does nothing
1278 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1281 void PF_precache_sound (void)
1286 if (sv.state != ss_loading)
1287 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1289 s = G_STRING(OFS_PARM0);
1290 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1291 PR_CheckEmptyString (s);
1293 for (i=0 ; i<MAX_SOUNDS ; i++)
1295 if (!sv.sound_precache[i])
1297 sv.sound_precache[i] = s;
1300 if (!strcmp(sv.sound_precache[i], s))
1303 Host_Error ("PF_precache_sound: overflow");
1306 void PF_precache_model (void)
1311 if (sv.state != ss_loading)
1312 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1314 s = G_STRING(OFS_PARM0);
1315 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1317 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1318 PR_CheckEmptyString (s);
1320 for (i=0 ; i<MAX_MODELS ; i++)
1322 if (!sv.model_precache[i])
1324 sv.model_precache[i] = s;
1325 sv.models[i] = Mod_ForName (s, true, false, false);
1328 if (!strcmp(sv.model_precache[i], s))
1331 Host_Error ("PF_precache_model: overflow");
1335 void PF_coredump (void)
1340 void PF_traceon (void)
1345 void PF_traceoff (void)
1350 void PF_eprint (void)
1352 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1359 float(float yaw, float dist) walkmove
1362 void PF_walkmove (void)
1370 ent = PROG_TO_EDICT(pr_global_struct->self);
1371 if (ent == sv.edicts)
1372 Host_Error("walkmove: can not modify world entity\n");
1374 Host_Error("walkmove: can not modify free entity\n");
1375 yaw = G_FLOAT(OFS_PARM0);
1376 dist = G_FLOAT(OFS_PARM1);
1378 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1380 G_FLOAT(OFS_RETURN) = 0;
1384 yaw = yaw*M_PI*2 / 360;
1386 move[0] = cos(yaw)*dist;
1387 move[1] = sin(yaw)*dist;
1390 // save program state, because SV_movestep may call other progs
1391 oldf = pr_xfunction;
1392 oldself = pr_global_struct->self;
1394 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1397 // restore program state
1398 pr_xfunction = oldf;
1399 pr_global_struct->self = oldself;
1409 void PF_droptofloor (void)
1415 ent = PROG_TO_EDICT(pr_global_struct->self);
1416 if (ent == sv.edicts)
1417 Host_Error("droptofloor: can not modify world entity\n");
1419 Host_Error("droptofloor: can not modify free entity\n");
1421 VectorCopy (ent->v->origin, end);
1424 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1426 if (trace.fraction == 1)
1427 G_FLOAT(OFS_RETURN) = 0;
1430 VectorCopy (trace.endpos, ent->v->origin);
1431 SV_LinkEdict (ent, false);
1432 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1433 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1434 G_FLOAT(OFS_RETURN) = 1;
1435 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1436 ent->e->suspendedinairflag = true;
1444 void(float style, string value) lightstyle
1447 void PF_lightstyle (void)
1454 style = G_FLOAT(OFS_PARM0);
1455 val = G_STRING(OFS_PARM1);
1457 // change the string in sv
1458 sv.lightstyles[style] = val;
1460 // send message to all clients on this server
1461 if (sv.state != ss_active)
1464 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1466 if (client->netconnection)
1468 MSG_WriteChar (&client->message, svc_lightstyle);
1469 MSG_WriteChar (&client->message,style);
1470 MSG_WriteString (&client->message, val);
1478 f = G_FLOAT(OFS_PARM0);
1480 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1482 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1484 void PF_floor (void)
1486 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1490 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1499 void PF_checkbottom (void)
1501 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1509 void PF_pointcontents (void)
1511 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1518 entity nextent(entity)
1521 void PF_nextent (void)
1526 i = G_EDICTNUM(OFS_PARM0);
1529 pr_xfunction->builtinsprofile++;
1531 if (i == sv.num_edicts)
1533 RETURN_EDICT(sv.edicts);
1549 Pick a vector for the player to shoot along
1550 vector aim(entity, missilespeed)
1555 edict_t *ent, *check, *bestent;
1556 vec3_t start, dir, end, bestdir;
1559 float dist, bestdist;
1562 ent = G_EDICT(OFS_PARM0);
1563 if (ent == sv.edicts)
1564 Host_Error("aim: can not use world entity\n");
1566 Host_Error("aim: can not use free entity\n");
1567 speed = G_FLOAT(OFS_PARM1);
1569 VectorCopy (ent->v->origin, start);
1572 // try sending a trace straight
1573 VectorCopy (pr_global_struct->v_forward, dir);
1574 VectorMA (start, 2048, dir, end);
1575 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1576 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1577 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1579 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1584 // try all possible entities
1585 VectorCopy (dir, bestdir);
1586 bestdist = sv_aim.value;
1589 check = NEXT_EDICT(sv.edicts);
1590 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1592 pr_xfunction->builtinsprofile++;
1593 if (check->v->takedamage != DAMAGE_AIM)
1597 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1598 continue; // don't aim at teammate
1599 for (j=0 ; j<3 ; j++)
1600 end[j] = check->v->origin[j]
1601 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1602 VectorSubtract (end, start, dir);
1603 VectorNormalize (dir);
1604 dist = DotProduct (dir, pr_global_struct->v_forward);
1605 if (dist < bestdist)
1606 continue; // to far to turn
1607 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1608 if (tr.ent == check)
1609 { // can shoot at this one
1617 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1618 dist = DotProduct (dir, pr_global_struct->v_forward);
1619 VectorScale (pr_global_struct->v_forward, dist, end);
1621 VectorNormalize (end);
1622 VectorCopy (end, G_VECTOR(OFS_RETURN));
1626 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1634 This was a major timewaster in progs, so it was converted to C
1637 void PF_changeyaw (void)
1640 float ideal, current, move, speed;
1642 ent = PROG_TO_EDICT(pr_global_struct->self);
1643 if (ent == sv.edicts)
1644 Host_Error("changeyaw: can not modify world entity\n");
1646 Host_Error("changeyaw: can not modify free entity\n");
1647 current = ANGLEMOD(ent->v->angles[1]);
1648 ideal = ent->v->ideal_yaw;
1649 speed = ent->v->yaw_speed;
1651 if (current == ideal)
1653 move = ideal - current;
1654 if (ideal > current)
1675 ent->v->angles[1] = ANGLEMOD (current + move);
1683 void PF_changepitch (void)
1686 float ideal, current, move, speed;
1689 ent = G_EDICT(OFS_PARM0);
1690 if (ent == sv.edicts)
1691 Host_Error("changepitch: can not modify world entity\n");
1693 Host_Error("changepitch: can not modify free entity\n");
1694 current = ANGLEMOD( ent->v->angles[0] );
1695 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1696 ideal = val->_float;
1699 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1702 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1703 speed = val->_float;
1706 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1710 if (current == ideal)
1712 move = ideal - current;
1713 if (ideal > current)
1734 ent->v->angles[0] = ANGLEMOD (current + move);
1738 ===============================================================================
1742 ===============================================================================
1745 #define MSG_BROADCAST 0 // unreliable to all
1746 #define MSG_ONE 1 // reliable to one (msg_entity)
1747 #define MSG_ALL 2 // reliable to all
1748 #define MSG_INIT 3 // write to the init string
1750 sizebuf_t *WriteDest (void)
1756 dest = G_FLOAT(OFS_PARM0);
1760 return &sv.datagram;
1763 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1764 entnum = NUM_FOR_EDICT(ent);
1765 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1766 Host_Error("WriteDest: tried to write to non-client\n");
1767 return &svs.clients[entnum-1].message;
1770 return &sv.reliable_datagram;
1776 Host_Error ("WriteDest: bad destination");
1783 void PF_WriteByte (void)
1785 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1788 void PF_WriteChar (void)
1790 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1793 void PF_WriteShort (void)
1795 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1798 void PF_WriteLong (void)
1800 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1803 void PF_WriteAngle (void)
1805 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1808 void PF_WriteCoord (void)
1810 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1813 void PF_WriteString (void)
1815 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1819 void PF_WriteEntity (void)
1821 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1824 //=============================================================================
1826 void PF_makestatic (void)
1831 ent = G_EDICT(OFS_PARM0);
1832 if (ent == sv.edicts)
1833 Host_Error("makestatic: can not modify world entity\n");
1835 Host_Error("makestatic: can not modify free entity\n");
1838 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1843 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1844 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1845 MSG_WriteShort (&sv.signon, ent->v->frame);
1849 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1850 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1851 MSG_WriteByte (&sv.signon, ent->v->frame);
1854 MSG_WriteByte (&sv.signon, ent->v->colormap);
1855 MSG_WriteByte (&sv.signon, ent->v->skin);
1856 for (i=0 ; i<3 ; i++)
1858 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1859 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1862 // throw the entity away now
1866 //=============================================================================
1873 void PF_setspawnparms (void)
1879 ent = G_EDICT(OFS_PARM0);
1880 i = NUM_FOR_EDICT(ent);
1881 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1883 Con_Printf("tried to setspawnparms on a non-client\n");
1887 // copy spawn parms out of the client_t
1888 client = svs.clients + i-1;
1889 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1890 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1898 void PF_changelevel (void)
1902 // make sure we don't issue two changelevels
1903 if (svs.changelevel_issued)
1905 svs.changelevel_issued = true;
1907 s = G_STRING(OFS_PARM0);
1908 Cbuf_AddText (va("changelevel %s\n",s));
1913 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1918 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1923 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1930 Returns a vector of length < 1
1935 void PF_randomvec (void)
1940 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1941 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1942 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1944 while (DotProduct(temp, temp) >= 1);
1945 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1952 Returns a color vector indicating the lighting at the requested point.
1954 (Internal Operation note: actually measures the light beneath the point, just like
1955 the model lighting on the client)
1960 void PF_GetLight (void)
1962 vec3_t ambientcolor, diffusecolor, diffusenormal;
1964 p = G_VECTOR(OFS_PARM0);
1965 VectorClear(ambientcolor);
1966 VectorClear(diffusecolor);
1967 VectorClear(diffusenormal);
1968 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1969 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1970 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1973 #define MAX_QC_CVARS 128
1974 cvar_t qc_cvar[MAX_QC_CVARS];
1977 void PF_registercvar (void)
1981 name = G_STRING(OFS_PARM0);
1982 value = G_STRING(OFS_PARM1);
1983 G_FLOAT(OFS_RETURN) = 0;
1984 // first check to see if it has already been defined
1985 if (Cvar_FindVar (name))
1988 // check for overlap with a command
1989 if (Cmd_Exists (name))
1991 Con_Printf ("PF_registercvar: %s is a command\n", name);
1995 if (currentqc_cvar >= MAX_QC_CVARS)
1996 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1998 // copy the name and value
1999 variable = &qc_cvar[currentqc_cvar++];
2000 variable->name = Z_Malloc (strlen(name)+1);
2001 strcpy (variable->name, name);
2002 variable->string = Z_Malloc (strlen(value)+1);
2003 strcpy (variable->string, value);
2004 variable->value = atof (value);
2006 Cvar_RegisterVariable(variable);
2007 G_FLOAT(OFS_RETURN) = 1; // success
2014 returns the minimum of two supplied floats
2021 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2023 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2024 else if (pr_argc >= 3)
2027 float f = G_FLOAT(OFS_PARM0);
2028 for (i = 1;i < pr_argc;i++)
2029 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2030 f = G_FLOAT((OFS_PARM0+i*3));
2031 G_FLOAT(OFS_RETURN) = f;
2034 Host_Error("min: must supply at least 2 floats\n");
2041 returns the maximum of two supplied floats
2048 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2050 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2051 else if (pr_argc >= 3)
2054 float f = G_FLOAT(OFS_PARM0);
2055 for (i = 1;i < pr_argc;i++)
2056 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2057 f = G_FLOAT((OFS_PARM0+i*3));
2058 G_FLOAT(OFS_RETURN) = f;
2061 Host_Error("max: must supply at least 2 floats\n");
2068 returns number bounded by supplied range
2070 min(min, value, max)
2073 void PF_bound (void)
2075 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2082 returns a raised to power b
2089 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2096 copies data from one entity to another
2098 copyentity(src, dst)
2101 void PF_copyentity (void)
2104 in = G_EDICT(OFS_PARM0);
2105 if (in == sv.edicts)
2106 Host_Error("copyentity: can not read world entity\n");
2108 Host_Error("copyentity: can not read free entity\n");
2109 out = G_EDICT(OFS_PARM1);
2110 if (out == sv.edicts)
2111 Host_Error("copyentity: can not modify world entity\n");
2113 Host_Error("copyentity: can not modify free entity\n");
2114 memcpy(out->v, in->v, progs->entityfields * 4);
2121 sets the color of a client and broadcasts the update to all connected clients
2123 setcolor(clientent, value)
2126 void PF_setcolor (void)
2132 entnum = G_EDICTNUM(OFS_PARM0);
2133 i = G_FLOAT(OFS_PARM1);
2135 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2137 Con_Printf ("tried to setcolor a non-client\n");
2141 client = svs.clients + entnum-1;
2142 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2145 client->old_colors = i;
2146 client->edict->v->team = (i & 15) + 1;
2148 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2149 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2150 MSG_WriteByte (&sv.reliable_datagram, i);
2157 effect(origin, modelname, startframe, framecount, framerate)
2160 void PF_effect (void)
2163 s = G_STRING(OFS_PARM1);
2165 Host_Error("effect: no model specified\n");
2167 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2170 void PF_te_blood (void)
2172 if (G_FLOAT(OFS_PARM2) < 1)
2174 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2175 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2179 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2181 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2182 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2183 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2185 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2188 void PF_te_bloodshower (void)
2190 if (G_FLOAT(OFS_PARM3) < 1)
2192 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2193 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2195 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2196 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2197 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2199 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2200 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2201 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2203 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2205 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2208 void PF_te_explosionrgb (void)
2210 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2211 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2213 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2217 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2218 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2219 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2222 void PF_te_particlecube (void)
2224 if (G_FLOAT(OFS_PARM3) < 1)
2226 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2227 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2231 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2237 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2241 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2243 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2244 // gravity true/false
2245 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2247 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2250 void PF_te_particlerain (void)
2252 if (G_FLOAT(OFS_PARM3) < 1)
2254 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2255 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2257 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2258 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2259 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2261 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2262 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2263 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2266 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2267 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2269 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2271 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2274 void PF_te_particlesnow (void)
2276 if (G_FLOAT(OFS_PARM3) < 1)
2278 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2279 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2286 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2287 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2289 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2290 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2291 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2293 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2295 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2298 void PF_te_spark (void)
2300 if (G_FLOAT(OFS_PARM2) < 1)
2302 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2303 MSG_WriteByte(&sv.datagram, TE_SPARK);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2306 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2307 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2309 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2310 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2311 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2313 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2316 void PF_te_gunshotquad (void)
2318 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2319 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2321 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2322 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2323 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2326 void PF_te_spikequad (void)
2328 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2329 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
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]);
2336 void PF_te_superspikequad (void)
2338 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2339 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2341 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2342 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2343 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2346 void PF_te_explosionquad (void)
2348 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2349 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2353 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2356 void PF_te_smallflash (void)
2358 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2359 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2363 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2366 void PF_te_customflash (void)
2368 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2370 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2371 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2375 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2377 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2379 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2381 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2382 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2383 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2386 void PF_te_gunshot (void)
2388 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2389 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2392 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2393 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2396 void PF_te_spike (void)
2398 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2399 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2402 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2403 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2406 void PF_te_superspike (void)
2408 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2409 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2413 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2416 void PF_te_explosion (void)
2418 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2419 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2423 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2426 void PF_te_tarexplosion (void)
2428 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2429 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2433 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2436 void PF_te_wizspike (void)
2438 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2439 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2441 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2442 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2443 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2446 void PF_te_knightspike (void)
2448 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2449 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2451 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2452 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2453 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2456 void PF_te_lavasplash (void)
2458 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2459 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2466 void PF_te_teleport (void)
2468 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2469 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2472 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2473 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2476 void PF_te_explosion2 (void)
2478 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2479 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2483 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2485 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2488 void PF_te_lightning1 (void)
2490 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2491 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2493 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2499 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2501 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2504 void PF_te_lightning2 (void)
2506 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2507 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2509 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2511 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2512 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2513 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2515 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2516 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2517 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2520 void PF_te_lightning3 (void)
2522 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2523 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2525 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2527 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2528 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2529 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2531 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2532 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2533 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2536 void PF_te_beam (void)
2538 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2539 MSG_WriteByte(&sv.datagram, TE_BEAM);
2541 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2543 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2544 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2545 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2547 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2548 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2549 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2552 void PF_te_plasmaburn (void)
2554 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2555 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2556 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2557 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2558 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2561 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2564 vec3_t v1, clipplanenormal, normal;
2565 vec_t clipplanedist, clipdist;
2567 if (surf->flags & SURF_PLANEBACK)
2568 VectorNegate(surf->plane->normal, normal);
2570 VectorCopy(surf->plane->normal, normal);
2571 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2573 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2574 VectorNormalizeFast(v1);
2575 CrossProduct(v1, normal, clipplanenormal);
2576 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2577 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2580 clipdist = -clipdist;
2581 VectorMA(out, clipdist, clipplanenormal, out);
2586 static msurface_t *getsurface(edict_t *ed, int surfnum)
2590 if (!ed || ed->e->free)
2592 modelindex = ed->v->modelindex;
2593 if (modelindex < 1 || modelindex >= MAX_MODELS)
2595 model = sv.models[modelindex];
2596 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2598 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2602 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2603 void PF_getsurfacenumpoints(void)
2606 // return 0 if no such surface
2607 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2609 G_FLOAT(OFS_RETURN) = 0;
2613 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2615 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2616 void PF_getsurfacepoint(void)
2621 VectorClear(G_VECTOR(OFS_RETURN));
2622 ed = G_EDICT(OFS_PARM0);
2623 if (!ed || ed->e->free)
2625 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2627 pointnum = G_FLOAT(OFS_PARM2);
2628 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2630 // FIXME: implement rotation/scaling
2631 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2633 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2634 void PF_getsurfacenormal(void)
2637 VectorClear(G_VECTOR(OFS_RETURN));
2638 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2640 // FIXME: implement rotation/scaling
2641 if (surf->flags & SURF_PLANEBACK)
2642 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2644 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2646 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2647 void PF_getsurfacetexture(void)
2650 G_INT(OFS_RETURN) = 0;
2651 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2653 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2655 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2656 void PF_getsurfacenearpoint(void)
2658 int surfnum, best, modelindex;
2660 vec_t dist, bestdist;
2665 G_FLOAT(OFS_RETURN) = -1;
2666 ed = G_EDICT(OFS_PARM0);
2667 point = G_VECTOR(OFS_PARM1);
2669 if (!ed || ed->e->free)
2671 modelindex = ed->v->modelindex;
2672 if (modelindex < 1 || modelindex >= MAX_MODELS)
2674 model = sv.models[modelindex];
2675 if (!model->brushq1.numsurfaces)
2678 // FIXME: implement rotation/scaling
2679 VectorSubtract(point, ed->v->origin, p);
2681 bestdist = 1000000000;
2682 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2684 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2685 dist = PlaneDiff(p, surf->plane);
2687 if (dist < bestdist)
2689 clippointtosurface(surf, p, clipped);
2690 VectorSubtract(clipped, p, clipped);
2691 dist += DotProduct(clipped, clipped);
2692 if (dist < bestdist)
2699 G_FLOAT(OFS_RETURN) = best;
2701 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2702 void PF_getsurfaceclippedpoint(void)
2707 VectorClear(G_VECTOR(OFS_RETURN));
2708 ed = G_EDICT(OFS_PARM0);
2709 if (!ed || ed->e->free)
2711 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2713 // FIXME: implement rotation/scaling
2714 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2715 clippointtosurface(surf, p, out);
2716 // FIXME: implement rotation/scaling
2717 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2720 #define MAX_PRFILES 256
2722 qfile_t *pr_files[MAX_PRFILES];
2724 void PR_Files_Init(void)
2726 memset(pr_files, 0, sizeof(pr_files));
2729 void PR_Files_CloseAll(void)
2732 for (i = 0;i < MAX_PRFILES;i++)
2735 FS_Close(pr_files[i]);
2740 //float(string s) stof = #81; // get numerical value from a string
2743 char string[STRINGTEMP_LENGTH];
2744 PF_VarString(0, string, sizeof(string));
2745 G_FLOAT(OFS_RETURN) = atof(string);
2748 //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
2752 char *modestring, *filename;
2753 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2754 if (pr_files[filenum] == NULL)
2756 if (filenum >= MAX_PRFILES)
2758 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2759 G_FLOAT(OFS_RETURN) = -2;
2762 mode = G_FLOAT(OFS_PARM1);
2765 case 0: // FILE_READ
2768 case 1: // FILE_APPEND
2771 case 2: // FILE_WRITE
2775 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2776 G_FLOAT(OFS_RETURN) = -3;
2779 filename = G_STRING(OFS_PARM0);
2780 // .. is parent directory on many platforms
2781 // / is parent directory on Amiga
2782 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2783 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2784 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2786 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2787 G_FLOAT(OFS_RETURN) = -4;
2790 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2791 if (pr_files[filenum] == NULL)
2792 G_FLOAT(OFS_RETURN) = -1;
2794 G_FLOAT(OFS_RETURN) = filenum;
2797 //void(float fhandle) fclose = #111; // closes a file
2798 void PF_fclose(void)
2800 int filenum = G_FLOAT(OFS_PARM0);
2801 if (filenum < 0 || filenum >= MAX_PRFILES)
2803 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2806 if (pr_files[filenum] == NULL)
2808 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2811 FS_Close(pr_files[filenum]);
2812 pr_files[filenum] = NULL;
2815 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2819 static char string[STRINGTEMP_LENGTH];
2820 int filenum = G_FLOAT(OFS_PARM0);
2821 if (filenum < 0 || filenum >= MAX_PRFILES)
2823 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2826 if (pr_files[filenum] == NULL)
2828 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2834 c = FS_Getc(pr_files[filenum]);
2835 if (c == '\r' || c == '\n' || c < 0)
2837 if (end < STRINGTEMP_LENGTH - 1)
2841 // remove \n following \r
2843 c = FS_Getc(pr_files[filenum]);
2844 if (developer.integer)
2845 Con_Printf("fgets: %s\n", string);
2847 G_INT(OFS_RETURN) = PR_SetString(string);
2849 G_INT(OFS_RETURN) = 0;
2852 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2856 char string[STRINGTEMP_LENGTH];
2857 int filenum = G_FLOAT(OFS_PARM0);
2858 if (filenum < 0 || filenum >= MAX_PRFILES)
2860 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2863 if (pr_files[filenum] == NULL)
2865 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2868 PF_VarString(1, string, sizeof(string));
2869 if ((stringlength = strlen(string)))
2870 FS_Write(pr_files[filenum], string, stringlength);
2871 if (developer.integer)
2872 Con_Printf("fputs: %s\n", string);
2875 //float(string s) strlen = #114; // returns how many characters are in a string
2876 void PF_strlen(void)
2879 s = G_STRING(OFS_PARM0);
2881 G_FLOAT(OFS_RETURN) = strlen(s);
2883 G_FLOAT(OFS_RETURN) = 0;
2886 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2887 void PF_strcat(void)
2889 char *s = PR_GetTempString();
2890 PF_VarString(0, s, STRINGTEMP_LENGTH);
2891 G_INT(OFS_RETURN) = PR_SetString(s);
2894 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2895 void PF_substring(void)
2897 int i, start, length;
2898 char *s, *string = PR_GetTempString();
2899 s = G_STRING(OFS_PARM0);
2900 start = G_FLOAT(OFS_PARM1);
2901 length = G_FLOAT(OFS_PARM2);
2904 for (i = 0;i < start && *s;i++, s++);
2905 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2908 G_INT(OFS_RETURN) = PR_SetString(string);
2911 //vector(string s) stov = #117; // returns vector value from a string
2914 char string[STRINGTEMP_LENGTH];
2915 PF_VarString(0, string, sizeof(string));
2916 Math_atov(string, G_VECTOR(OFS_RETURN));
2919 //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)
2920 void PF_strzone(void)
2923 in = G_STRING(OFS_PARM0);
2924 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2926 G_INT(OFS_RETURN) = PR_SetString(out);
2929 //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!!!)
2930 void PF_strunzone(void)
2932 Mem_Free(G_STRING(OFS_PARM0));
2935 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2936 //this function originally written by KrimZon, made shorter by LordHavoc
2937 void PF_clientcommand (void)
2939 client_t *temp_client;
2942 //find client for this entity
2943 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2944 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2946 Con_Printf("PF_clientcommand: entity is not a client");
2950 temp_client = host_client;
2951 host_client = svs.clients + i;
2952 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2953 host_client = temp_client;
2956 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2957 //this function originally written by KrimZon, made shorter by LordHavoc
2958 char **tokens = NULL;
2959 int max_tokens, num_tokens = 0;
2960 void PF_tokenize (void)
2964 str = G_STRING(OFS_PARM0);
2969 for (i=0;i<num_tokens;i++)
2975 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2976 max_tokens = strlen(str);
2978 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2980 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2981 strcpy(tokens[num_tokens], com_token);
2984 G_FLOAT(OFS_RETURN) = num_tokens;
2987 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2988 //this function originally written by KrimZon, made shorter by LordHavoc
2991 int token_num = G_FLOAT(OFS_PARM0);
2992 if (token_num >= 0 && token_num < num_tokens)
2993 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2995 G_INT(OFS_RETURN) = PR_SetString("");
2998 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
2999 void PF_setattachment (void)
3001 edict_t *e = G_EDICT(OFS_PARM0);
3002 edict_t *tagentity = G_EDICT(OFS_PARM1);
3003 char *tagname = G_STRING(OFS_PARM2);
3009 Host_Error("setattachment: can not modify world entity\n");
3011 Host_Error("setattachment: can not modify free entity\n");
3013 if (tagentity == NULL)
3014 tagentity = sv.edicts;
3016 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3018 v->edict = EDICT_TO_PROG(tagentity);
3020 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3023 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3025 modelindex = (int)tagentity->v->modelindex;
3026 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3028 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3029 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3030 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3032 if (v->_float == 0 && model->alias.aliasnum_tags)
3033 for (i = 0;i < model->alias.aliasnum_tags;i++)
3034 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3037 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
3040 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
3045 builtin_t pr_builtin[] =
3048 PF_makevectors, // #1 void(entity e) makevectors
3049 PF_setorigin, // #2 void(entity e, vector o) setorigin
3050 PF_setmodel, // #3 void(entity e, string m) setmodel
3051 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3052 NULL, // #5 void(entity e, vector min, vector max) setabssize
3053 PF_break, // #6 void() break
3054 PF_random, // #7 float() random
3055 PF_sound, // #8 void(entity e, float chan, string samp) sound
3056 PF_normalize, // #9 vector(vector v) normalize
3057 PF_error, // #10 void(string e) error
3058 PF_objerror, // #11 void(string e) objerror
3059 PF_vlen, // #12 float(vector v) vlen
3060 PF_vectoyaw, // #13 float(vector v) vectoyaw
3061 PF_Spawn, // #14 entity() spawn
3062 PF_Remove, // #15 void(entity e) remove
3063 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3064 PF_checkclient, // #17 entity() clientlist
3065 PF_Find, // #18 entity(entity start, .string fld, string match) find
3066 PF_precache_sound, // #19 void(string s) precache_sound
3067 PF_precache_model, // #20 void(string s) precache_model
3068 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3069 PF_findradius, // #22 entity(vector org, float rad) findradius
3070 PF_bprint, // #23 void(string s) bprint
3071 PF_sprint, // #24 void(entity client, string s) sprint
3072 PF_dprint, // #25 void(string s) dprint
3073 PF_ftos, // #26 void(string s) ftos
3074 PF_vtos, // #27 void(string s) vtos
3075 PF_coredump, // #28 void() coredump
3076 PF_traceon, // #29 void() traceon
3077 PF_traceoff, // #30 void() traceoff
3078 PF_eprint, // #31 void(entity e) eprint
3079 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3081 PF_droptofloor, // #34 float() droptofloor
3082 PF_lightstyle, // #35 void(float style, string value) lightstyle
3083 PF_rint, // #36 float(float v) rint
3084 PF_floor, // #37 float(float v) floor
3085 PF_ceil, // #38 float(float v) ceil
3087 PF_checkbottom, // #40 float(entity e) checkbottom
3088 PF_pointcontents , // #41 float(vector v) pointcontents
3090 PF_fabs, // #43 float(float f) fabs
3091 PF_aim, // #44 vector(entity e, float speed) aim
3092 PF_cvar, // #45 float(string s) cvar
3093 PF_localcmd, // #46 void(string s) localcmd
3094 PF_nextent, // #47 entity(entity e) nextent
3095 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3096 PF_changeyaw, // #49 void() ChangeYaw
3098 PF_vectoangles, // #51 vector(vector v) vectoangles
3099 PF_WriteByte, // #52 void(float to, float f) WriteByte
3100 PF_WriteChar, // #53 void(float to, float f) WriteChar
3101 PF_WriteShort, // #54 void(float to, float f) WriteShort
3102 PF_WriteLong, // #55 void(float to, float f) WriteLong
3103 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3104 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3105 PF_WriteString, // #58 void(float to, string s) WriteString
3106 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3107 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3108 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3109 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3110 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3111 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3112 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3114 SV_MoveToGoal, // #67 void(float step) movetogoal
3115 PF_precache_file, // #68 string(string s) precache_file
3116 PF_makestatic, // #69 void(entity e) makestatic
3117 PF_changelevel, // #70 void(string s) changelevel
3119 PF_cvar_set, // #72 void(string var, string val) cvar_set
3120 PF_centerprint, // #73 void(entity client, strings) centerprint
3121 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3122 PF_precache_model, // #75 string(string s) precache_model2
3123 PF_precache_sound, // #76 string(string s) precache_sound2
3124 PF_precache_file, // #77 string(string s) precache_file2
3125 PF_setspawnparms, // #78 void(entity e) setspawnparms
3128 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3137 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3138 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3139 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3140 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3141 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3142 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3143 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3144 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3145 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3146 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3157 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3158 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3159 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3160 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3161 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3162 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3163 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3164 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3165 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3166 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3167 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3168 a a a a a a a a // #120-199
3169 a a a a a a a a a a // #200-299
3170 a a a a a a a a a a // #300-399
3171 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3172 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3173 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3174 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3175 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3176 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3177 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3178 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3179 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3180 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3181 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3182 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3183 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3184 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3185 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3186 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3187 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3188 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3189 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3190 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3191 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3192 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3193 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3194 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3195 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3196 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3197 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3198 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3199 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3200 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3201 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3202 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3203 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3204 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3205 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3206 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3207 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3208 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3209 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3210 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3211 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3212 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3213 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3214 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3221 a a a a a // #450-499 (LordHavoc)
3224 builtin_t *pr_builtins = pr_builtin;
3225 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3227 void PR_Cmd_Init(void)
3229 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3233 void PR_Cmd_Reset(void)
3235 Mem_EmptyPool(pr_strings_mempool);
3236 PR_Files_CloseAll();