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 "
95 "DP_MOVETYPEBOUNCEMISSILE "
101 "DP_QC_FINDCHAINFLOAT "
107 "DP_QC_SINCOSSQRTPOW "
110 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
111 "DP_QC_TRACE_MOVETYPE_HITMODEL "
112 "DP_QC_VECTORVECTORS "
118 "DP_SV_DRAWONLYTOCLIENT "
120 "DP_SV_EXTERIORMODELTOCLIENT "
121 "DP_SV_NODRAWTOCLIENT "
122 "DP_SV_PLAYERPHYSICS "
128 "DP_TE_EXPLOSIONRGB "
130 "DP_TE_PARTICLECUBE "
131 "DP_TE_PARTICLERAIN "
132 "DP_TE_PARTICLESNOW "
134 "DP_TE_QUADEFFECTS1 "
137 "DP_TE_STANDARDEFFECTBUILTINS "
140 "KRIMZON_SV_PARSECLIENTCOMMAND "
146 qboolean checkextension(char *name)
151 for (e = ENGINE_EXTENSIONS;*e;e++)
158 while (*e && *e != ' ')
160 if (e - start == len)
161 if (!strncasecmp(start, name, len))
171 returns true if the extension is supported by the server
173 checkextension(extensionname)
176 void PF_checkextension (void)
178 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
185 This is a TERMINAL error, which will kill off the entire server.
194 char string[STRINGTEMP_LENGTH];
196 PF_VarString(0, string, sizeof(string));
197 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
198 ed = PROG_TO_EDICT(pr_global_struct->self);
201 Host_Error ("Program error");
208 Dumps out self, then an error message. The program is aborted and self is
209 removed, but the level can continue.
214 void PF_objerror (void)
217 char string[STRINGTEMP_LENGTH];
219 PF_VarString(0, string, sizeof(string));
220 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
221 ed = PROG_TO_EDICT(pr_global_struct->self);
231 Writes new values for v_forward, v_up, and v_right based on angles
235 void PF_makevectors (void)
237 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
244 Writes new values for v_forward, v_up, and v_right based on the given forward vector
245 vectorvectors(vector, vector)
248 void PF_vectorvectors (void)
250 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
251 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
258 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.
260 setorigin (entity, origin)
263 void PF_setorigin (void)
268 e = G_EDICT(OFS_PARM0);
270 Host_Error("setorigin: can not modify world entity\n");
272 Host_Error("setorigin: can not modify free entity\n");
273 org = G_VECTOR(OFS_PARM1);
274 VectorCopy (org, e->v->origin);
275 SV_LinkEdict (e, false);
279 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
283 for (i=0 ; i<3 ; i++)
285 Host_Error ("backwards mins/maxs");
287 // set derived values
288 VectorCopy (min, e->v->mins);
289 VectorCopy (max, e->v->maxs);
290 VectorSubtract (max, min, e->v->size);
292 SV_LinkEdict (e, false);
299 the size box is rotated by the current angle
300 LordHavoc: no it isn't...
302 setsize (entity, minvector, maxvector)
305 void PF_setsize (void)
310 e = G_EDICT(OFS_PARM0);
312 Host_Error("setsize: can not modify world entity\n");
314 Host_Error("setsize: can not modify free entity\n");
315 min = G_VECTOR(OFS_PARM1);
316 max = G_VECTOR(OFS_PARM2);
317 SetMinMaxSize (e, min, max, false);
325 setmodel(entity, model)
328 void PF_setmodel (void)
335 e = G_EDICT(OFS_PARM0);
337 Host_Error("setmodel: can not modify world entity\n");
339 Host_Error("setmodel: can not modify free entity\n");
340 m = G_STRING(OFS_PARM1);
342 // check to see if model was properly precached
343 for (i=0, check = sv.model_precache ; *check ; i++, check++)
344 if (!strcmp(*check, m))
348 Host_Error ("no precache: %s\n", m);
351 e->v->model = PR_SetString(*check);
352 e->v->modelindex = i;
354 mod = sv.models[ (int)e->v->modelindex];
357 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
359 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
366 broadcast print to everyone on server
371 void PF_bprint (void)
373 char string[STRINGTEMP_LENGTH];
374 PF_VarString(0, string, sizeof(string));
375 SV_BroadcastPrintf("%s", string);
382 single print to a specific client
384 sprint(clientent, value)
387 void PF_sprint (void)
391 char string[STRINGTEMP_LENGTH];
393 entnum = G_EDICTNUM(OFS_PARM0);
395 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
397 Con_Printf ("tried to sprint to a non-client\n");
401 client = svs.clients + entnum-1;
402 if (!client->netconnection)
404 PF_VarString(1, string, sizeof(string));
405 MSG_WriteChar(&client->message,svc_print);
406 MSG_WriteString(&client->message, string);
414 single print to a specific client
416 centerprint(clientent, value)
419 void PF_centerprint (void)
423 char string[STRINGTEMP_LENGTH];
425 entnum = G_EDICTNUM(OFS_PARM0);
427 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
429 Con_Printf ("tried to sprint to a non-client\n");
433 client = svs.clients + entnum-1;
434 if (!client->netconnection)
436 PF_VarString(1, string, sizeof(string));
437 MSG_WriteChar(&client->message,svc_centerprint);
438 MSG_WriteString(&client->message, string);
446 vector normalize(vector)
449 void PF_normalize (void)
455 value1 = G_VECTOR(OFS_PARM0);
457 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
461 newvalue[0] = newvalue[1] = newvalue[2] = 0;
465 newvalue[0] = value1[0] * new;
466 newvalue[1] = value1[1] * new;
467 newvalue[2] = value1[2] * new;
470 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
485 value1 = G_VECTOR(OFS_PARM0);
487 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
490 G_FLOAT(OFS_RETURN) = new;
497 float vectoyaw(vector)
500 void PF_vectoyaw (void)
505 value1 = G_VECTOR(OFS_PARM0);
507 if (value1[1] == 0 && value1[0] == 0)
511 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
516 G_FLOAT(OFS_RETURN) = yaw;
524 vector vectoangles(vector)
527 void PF_vectoangles (void)
533 value1 = G_VECTOR(OFS_PARM0);
535 if (value1[1] == 0 && value1[0] == 0)
545 // LordHavoc: optimized a bit
548 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
552 else if (value1[1] > 0)
557 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
558 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
563 G_FLOAT(OFS_RETURN+0) = pitch;
564 G_FLOAT(OFS_RETURN+1) = yaw;
565 G_FLOAT(OFS_RETURN+2) = 0;
572 Returns a number from 0<= num < 1
577 void PF_random (void)
581 num = (rand ()&0x7fff) / ((float)0x7fff);
583 G_FLOAT(OFS_RETURN) = num;
590 particle(origin, color, count)
593 void PF_particle (void)
599 org = G_VECTOR(OFS_PARM0);
600 dir = G_VECTOR(OFS_PARM1);
601 color = G_FLOAT(OFS_PARM2);
602 count = G_FLOAT(OFS_PARM3);
603 SV_StartParticle (org, dir, color, count);
613 void PF_ambientsound (void)
618 float vol, attenuation;
619 int i, soundnum, large;
621 pos = G_VECTOR (OFS_PARM0);
622 samp = G_STRING(OFS_PARM1);
623 vol = G_FLOAT(OFS_PARM2);
624 attenuation = G_FLOAT(OFS_PARM3);
626 // check to see if samp was properly precached
627 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
628 if (!strcmp(*check,samp))
633 Con_Printf ("no precache: %s\n", samp);
641 // add an svc_spawnambient command to the level signon packet
644 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
646 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
648 for (i=0 ; i<3 ; i++)
649 MSG_WriteDPCoord(&sv.signon, pos[i]);
652 MSG_WriteShort (&sv.signon, soundnum);
654 MSG_WriteByte (&sv.signon, soundnum);
656 MSG_WriteByte (&sv.signon, vol*255);
657 MSG_WriteByte (&sv.signon, attenuation*64);
665 Each entity can have eight independant sound sources, like voice,
668 Channel 0 is an auto-allocate channel, the others override anything
669 already running on that entity/channel pair.
671 An attenuation of 0 will play full volume everywhere in the level.
672 Larger attenuations will drop off.
684 entity = G_EDICT(OFS_PARM0);
685 channel = G_FLOAT(OFS_PARM1);
686 sample = G_STRING(OFS_PARM2);
687 volume = G_FLOAT(OFS_PARM3) * 255;
688 attenuation = G_FLOAT(OFS_PARM4);
690 if (volume < 0 || volume > 255)
691 Host_Error ("SV_StartSound: volume = %i", volume);
693 if (attenuation < 0 || attenuation > 4)
694 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
696 if (channel < 0 || channel > 7)
697 Host_Error ("SV_StartSound: channel = %i", channel);
699 SV_StartSound (entity, channel, sample, volume, attenuation);
711 Host_Error ("break statement");
718 Used for use tracing and shot targeting
719 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
720 if the tryents flag is set.
722 traceline (vector1, vector2, tryents)
725 void PF_traceline (void)
732 pr_xfunction->builtinsprofile += 30;
734 v1 = G_VECTOR(OFS_PARM0);
735 v2 = G_VECTOR(OFS_PARM1);
736 nomonsters = G_FLOAT(OFS_PARM2);
737 ent = G_EDICT(OFS_PARM3);
739 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
741 pr_global_struct->trace_allsolid = trace.allsolid;
742 pr_global_struct->trace_startsolid = trace.startsolid;
743 pr_global_struct->trace_fraction = trace.fraction;
744 pr_global_struct->trace_inwater = trace.inwater;
745 pr_global_struct->trace_inopen = trace.inopen;
746 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
747 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
748 pr_global_struct->trace_plane_dist = trace.plane.dist;
750 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
752 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
753 // FIXME: add trace_endcontents
761 Used for use tracing and shot targeting
762 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
763 if the tryents flag is set.
765 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
768 // LordHavoc: added this for my own use, VERY useful, similar to traceline
769 void PF_tracebox (void)
771 float *v1, *v2, *m1, *m2;
776 pr_xfunction->builtinsprofile += 30;
778 v1 = G_VECTOR(OFS_PARM0);
779 m1 = G_VECTOR(OFS_PARM1);
780 m2 = G_VECTOR(OFS_PARM2);
781 v2 = G_VECTOR(OFS_PARM3);
782 nomonsters = G_FLOAT(OFS_PARM4);
783 ent = G_EDICT(OFS_PARM5);
785 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
787 pr_global_struct->trace_allsolid = trace.allsolid;
788 pr_global_struct->trace_startsolid = trace.startsolid;
789 pr_global_struct->trace_fraction = trace.fraction;
790 pr_global_struct->trace_inwater = trace.inwater;
791 pr_global_struct->trace_inopen = trace.inopen;
792 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
793 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
794 pr_global_struct->trace_plane_dist = trace.plane.dist;
796 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
798 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
801 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
802 void PF_TraceToss (void)
808 pr_xfunction->builtinsprofile += 600;
810 ent = G_EDICT(OFS_PARM0);
811 if (ent == sv.edicts)
812 Host_Error("tracetoss: can not use world entity\n");
813 ignore = G_EDICT(OFS_PARM1);
815 trace = SV_Trace_Toss (ent, ignore);
817 pr_global_struct->trace_allsolid = trace.allsolid;
818 pr_global_struct->trace_startsolid = trace.startsolid;
819 pr_global_struct->trace_fraction = trace.fraction;
820 pr_global_struct->trace_inwater = trace.inwater;
821 pr_global_struct->trace_inopen = trace.inopen;
822 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
823 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
824 pr_global_struct->trace_plane_dist = trace.plane.dist;
826 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
828 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
836 Returns true if the given entity can move to the given position from it's
837 current position by walking or rolling.
839 scalar checkpos (entity, vector)
842 void PF_checkpos (void)
846 //============================================================================
849 qbyte checkpvs[MAX_MAP_LEAFS/8];
851 int PF_newcheckclient (int check)
857 // cycle to the next one
859 check = bound(1, check, svs.maxclients);
860 if (check == svs.maxclients)
868 pr_xfunction->builtinsprofile++;
870 if (i == svs.maxclients+1)
872 // look up the client's edict
874 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
875 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
877 // found a valid client (possibly the same one again)
881 // get the PVS for the entity
882 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
884 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
885 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
894 Returns a client (or object that has a client enemy) that would be a
897 If there is more than one valid option, they are cycled each frame
899 If (self.origin + self.viewofs) is not in the PVS of the current target,
900 it is not returned at all.
905 int c_invis, c_notvis;
906 void PF_checkclient (void)
911 // find a new check if on a new frame
912 if (sv.time - sv.lastchecktime >= 0.1)
914 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
915 sv.lastchecktime = sv.time;
918 // return check if it might be visible
919 ent = EDICT_NUM(sv.lastcheck);
920 if (ent->e->free || ent->v->health <= 0)
922 RETURN_EDICT(sv.edicts);
926 // if current entity can't possibly see the check entity, return 0
927 self = PROG_TO_EDICT(pr_global_struct->self);
928 VectorAdd(self->v->origin, self->v->view_ofs, view);
929 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
932 RETURN_EDICT(sv.edicts);
936 // might be able to see it
941 //============================================================================
948 Sends text over to the client's execution buffer
950 stuffcmd (clientent, value)
953 void PF_stuffcmd (void)
959 entnum = G_EDICTNUM(OFS_PARM0);
960 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
962 Con_Printf("Can't stuffcmd to a non-client");
965 str = G_STRING(OFS_PARM1);
968 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
969 Host_ClientCommands ("%s", str);
977 Sends text to server console
982 void PF_localcmd (void)
984 Cbuf_AddText(G_STRING(OFS_PARM0));
996 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1006 void PF_cvar_set (void)
1008 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1015 Returns a chain of entities that have origins within a spherical area
1017 findradius (origin, radius)
1020 void PF_findradius (void)
1022 edict_t *ent, *chain;
1029 chain = (edict_t *)sv.edicts;
1031 org = G_VECTOR(OFS_PARM0);
1032 radius = G_FLOAT(OFS_PARM1);
1033 radius2 = radius * radius;
1035 ent = NEXT_EDICT(sv.edicts);
1036 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1038 pr_xfunction->builtinsprofile++;
1041 if (ent->v->solid == SOLID_NOT)
1044 // LordHavoc: compare against bounding box rather than center,
1045 // and use DotProduct instead of Length, major speedup
1046 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1047 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1048 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1049 if (DotProduct(eorg, eorg) > radius2)
1052 ent->v->chain = EDICT_TO_PROG(chain);
1056 RETURN_EDICT(chain);
1065 void PF_dprint (void)
1067 char string[STRINGTEMP_LENGTH];
1068 if (developer.integer)
1070 PF_VarString(0, string, sizeof(string));
1071 Con_Printf("%s",string);
1079 v = G_FLOAT(OFS_PARM0);
1081 s = PR_GetTempString();
1082 if ((float)((int)v) == v)
1083 sprintf(s, "%i", (int)v);
1085 sprintf(s, "%f", v);
1086 G_INT(OFS_RETURN) = PR_SetString(s);
1092 v = G_FLOAT(OFS_PARM0);
1093 G_FLOAT(OFS_RETURN) = fabs(v);
1099 s = PR_GetTempString();
1100 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1101 G_INT(OFS_RETURN) = PR_SetString(s);
1107 s = PR_GetTempString();
1108 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1109 G_INT(OFS_RETURN) = PR_SetString(s);
1112 void PF_Spawn (void)
1115 pr_xfunction->builtinsprofile += 20;
1120 void PF_Remove (void)
1123 pr_xfunction->builtinsprofile += 20;
1125 ed = G_EDICT(OFS_PARM0);
1126 if (ed == sv.edicts)
1127 Host_Error("remove: tried to remove world\n");
1128 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1129 Host_Error("remove: tried to remove a client\n");
1130 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1131 if (ed->e->free && developer.integer)
1132 Con_Printf("remove: tried to remove an entity that was already removed\n");
1137 // entity (entity start, .string field, string match) find = #5;
1145 e = G_EDICTNUM(OFS_PARM0);
1146 f = G_INT(OFS_PARM1);
1147 s = G_STRING(OFS_PARM2);
1150 RETURN_EDICT(sv.edicts);
1154 for (e++ ; e < sv.num_edicts ; e++)
1156 pr_xfunction->builtinsprofile++;
1170 RETURN_EDICT(sv.edicts);
1173 // LordHavoc: added this for searching float, int, and entity reference fields
1174 void PF_FindFloat (void)
1181 e = G_EDICTNUM(OFS_PARM0);
1182 f = G_INT(OFS_PARM1);
1183 s = G_FLOAT(OFS_PARM2);
1185 for (e++ ; e < sv.num_edicts ; e++)
1187 pr_xfunction->builtinsprofile++;
1191 if (E_FLOAT(ed,f) == s)
1198 RETURN_EDICT(sv.edicts);
1201 // chained search for strings in entity fields
1202 // entity(.string field, string match) findchain = #402;
1203 void PF_findchain (void)
1208 edict_t *ent, *chain;
1210 chain = (edict_t *)sv.edicts;
1212 f = G_INT(OFS_PARM0);
1213 s = G_STRING(OFS_PARM1);
1216 RETURN_EDICT(sv.edicts);
1220 ent = NEXT_EDICT(sv.edicts);
1221 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1223 pr_xfunction->builtinsprofile++;
1226 t = E_STRING(ent,f);
1232 ent->v->chain = EDICT_TO_PROG(chain);
1236 RETURN_EDICT(chain);
1239 // LordHavoc: chained search for float, int, and entity reference fields
1240 // entity(.string field, float match) findchainfloat = #403;
1241 void PF_findchainfloat (void)
1246 edict_t *ent, *chain;
1248 chain = (edict_t *)sv.edicts;
1250 f = G_INT(OFS_PARM0);
1251 s = G_FLOAT(OFS_PARM1);
1253 ent = NEXT_EDICT(sv.edicts);
1254 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1256 pr_xfunction->builtinsprofile++;
1259 if (E_FLOAT(ent,f) != s)
1262 ent->v->chain = EDICT_TO_PROG(chain);
1266 RETURN_EDICT(chain);
1269 void PR_CheckEmptyString (char *s)
1272 Host_Error ("Bad string");
1275 void PF_precache_file (void)
1276 { // precache_file is only used to copy files with qcc, it does nothing
1277 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1280 void PF_precache_sound (void)
1285 if (sv.state != ss_loading)
1286 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1288 s = G_STRING(OFS_PARM0);
1289 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1290 PR_CheckEmptyString (s);
1292 for (i=0 ; i<MAX_SOUNDS ; i++)
1294 if (!sv.sound_precache[i])
1296 sv.sound_precache[i] = s;
1299 if (!strcmp(sv.sound_precache[i], s))
1302 Host_Error ("PF_precache_sound: overflow");
1305 void PF_precache_model (void)
1310 if (sv.state != ss_loading)
1311 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1313 s = G_STRING(OFS_PARM0);
1314 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1316 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1317 PR_CheckEmptyString (s);
1319 for (i=0 ; i<MAX_MODELS ; i++)
1321 if (!sv.model_precache[i])
1323 sv.model_precache[i] = s;
1324 sv.models[i] = Mod_ForName (s, true, false, false);
1327 if (!strcmp(sv.model_precache[i], s))
1330 Host_Error ("PF_precache_model: overflow");
1334 void PF_coredump (void)
1339 void PF_traceon (void)
1344 void PF_traceoff (void)
1349 void PF_eprint (void)
1351 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1358 float(float yaw, float dist) walkmove
1361 void PF_walkmove (void)
1369 ent = PROG_TO_EDICT(pr_global_struct->self);
1370 if (ent == sv.edicts)
1371 Host_Error("walkmove: can not modify world entity\n");
1373 Host_Error("walkmove: can not modify free entity\n");
1374 yaw = G_FLOAT(OFS_PARM0);
1375 dist = G_FLOAT(OFS_PARM1);
1377 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1379 G_FLOAT(OFS_RETURN) = 0;
1383 yaw = yaw*M_PI*2 / 360;
1385 move[0] = cos(yaw)*dist;
1386 move[1] = sin(yaw)*dist;
1389 // save program state, because SV_movestep may call other progs
1390 oldf = pr_xfunction;
1391 oldself = pr_global_struct->self;
1393 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1396 // restore program state
1397 pr_xfunction = oldf;
1398 pr_global_struct->self = oldself;
1408 void PF_droptofloor (void)
1414 ent = PROG_TO_EDICT(pr_global_struct->self);
1415 if (ent == sv.edicts)
1416 Host_Error("droptofloor: can not modify world entity\n");
1418 Host_Error("droptofloor: can not modify free entity\n");
1420 VectorCopy (ent->v->origin, end);
1423 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1425 if (trace.fraction == 1)
1426 G_FLOAT(OFS_RETURN) = 0;
1429 VectorCopy (trace.endpos, ent->v->origin);
1430 SV_LinkEdict (ent, false);
1431 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1432 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1433 G_FLOAT(OFS_RETURN) = 1;
1434 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1435 ent->e->suspendedinairflag = true;
1443 void(float style, string value) lightstyle
1446 void PF_lightstyle (void)
1453 style = G_FLOAT(OFS_PARM0);
1454 val = G_STRING(OFS_PARM1);
1456 // change the string in sv
1457 sv.lightstyles[style] = val;
1459 // send message to all clients on this server
1460 if (sv.state != ss_active)
1463 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1465 if (client->netconnection)
1467 MSG_WriteChar (&client->message, svc_lightstyle);
1468 MSG_WriteChar (&client->message,style);
1469 MSG_WriteString (&client->message, val);
1477 f = G_FLOAT(OFS_PARM0);
1479 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1481 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1483 void PF_floor (void)
1485 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1489 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1498 void PF_checkbottom (void)
1500 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1508 void PF_pointcontents (void)
1510 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1517 entity nextent(entity)
1520 void PF_nextent (void)
1525 i = G_EDICTNUM(OFS_PARM0);
1528 pr_xfunction->builtinsprofile++;
1530 if (i == sv.num_edicts)
1532 RETURN_EDICT(sv.edicts);
1548 Pick a vector for the player to shoot along
1549 vector aim(entity, missilespeed)
1554 edict_t *ent, *check, *bestent;
1555 vec3_t start, dir, end, bestdir;
1558 float dist, bestdist;
1561 ent = G_EDICT(OFS_PARM0);
1562 if (ent == sv.edicts)
1563 Host_Error("aim: can not use world entity\n");
1565 Host_Error("aim: can not use free entity\n");
1566 speed = G_FLOAT(OFS_PARM1);
1568 VectorCopy (ent->v->origin, start);
1571 // try sending a trace straight
1572 VectorCopy (pr_global_struct->v_forward, dir);
1573 VectorMA (start, 2048, dir, end);
1574 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1575 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1576 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1578 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1583 // try all possible entities
1584 VectorCopy (dir, bestdir);
1585 bestdist = sv_aim.value;
1588 check = NEXT_EDICT(sv.edicts);
1589 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1591 pr_xfunction->builtinsprofile++;
1592 if (check->v->takedamage != DAMAGE_AIM)
1596 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1597 continue; // don't aim at teammate
1598 for (j=0 ; j<3 ; j++)
1599 end[j] = check->v->origin[j]
1600 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1601 VectorSubtract (end, start, dir);
1602 VectorNormalize (dir);
1603 dist = DotProduct (dir, pr_global_struct->v_forward);
1604 if (dist < bestdist)
1605 continue; // to far to turn
1606 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1607 if (tr.ent == check)
1608 { // can shoot at this one
1616 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1617 dist = DotProduct (dir, pr_global_struct->v_forward);
1618 VectorScale (pr_global_struct->v_forward, dist, end);
1620 VectorNormalize (end);
1621 VectorCopy (end, G_VECTOR(OFS_RETURN));
1625 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1633 This was a major timewaster in progs, so it was converted to C
1636 void PF_changeyaw (void)
1639 float ideal, current, move, speed;
1641 ent = PROG_TO_EDICT(pr_global_struct->self);
1642 if (ent == sv.edicts)
1643 Host_Error("changeyaw: can not modify world entity\n");
1645 Host_Error("changeyaw: can not modify free entity\n");
1646 current = ANGLEMOD(ent->v->angles[1]);
1647 ideal = ent->v->ideal_yaw;
1648 speed = ent->v->yaw_speed;
1650 if (current == ideal)
1652 move = ideal - current;
1653 if (ideal > current)
1674 ent->v->angles[1] = ANGLEMOD (current + move);
1682 void PF_changepitch (void)
1685 float ideal, current, move, speed;
1688 ent = G_EDICT(OFS_PARM0);
1689 if (ent == sv.edicts)
1690 Host_Error("changepitch: can not modify world entity\n");
1692 Host_Error("changepitch: can not modify free entity\n");
1693 current = ANGLEMOD( ent->v->angles[0] );
1694 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1695 ideal = val->_float;
1698 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1701 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1702 speed = val->_float;
1705 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1709 if (current == ideal)
1711 move = ideal - current;
1712 if (ideal > current)
1733 ent->v->angles[0] = ANGLEMOD (current + move);
1737 ===============================================================================
1741 ===============================================================================
1744 #define MSG_BROADCAST 0 // unreliable to all
1745 #define MSG_ONE 1 // reliable to one (msg_entity)
1746 #define MSG_ALL 2 // reliable to all
1747 #define MSG_INIT 3 // write to the init string
1749 sizebuf_t *WriteDest (void)
1755 dest = G_FLOAT(OFS_PARM0);
1759 return &sv.datagram;
1762 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1763 entnum = NUM_FOR_EDICT(ent);
1764 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1765 Host_Error("WriteDest: tried to write to non-client\n");
1766 return &svs.clients[entnum-1].message;
1769 return &sv.reliable_datagram;
1775 Host_Error ("WriteDest: bad destination");
1782 void PF_WriteByte (void)
1784 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1787 void PF_WriteChar (void)
1789 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1792 void PF_WriteShort (void)
1794 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1797 void PF_WriteLong (void)
1799 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1802 void PF_WriteAngle (void)
1804 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1807 void PF_WriteCoord (void)
1809 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1812 void PF_WriteString (void)
1814 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1818 void PF_WriteEntity (void)
1820 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1823 //=============================================================================
1825 void PF_makestatic (void)
1830 ent = G_EDICT(OFS_PARM0);
1831 if (ent == sv.edicts)
1832 Host_Error("makestatic: can not modify world entity\n");
1834 Host_Error("makestatic: can not modify free entity\n");
1837 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1842 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1843 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1844 MSG_WriteShort (&sv.signon, ent->v->frame);
1848 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1849 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1850 MSG_WriteByte (&sv.signon, ent->v->frame);
1853 MSG_WriteByte (&sv.signon, ent->v->colormap);
1854 MSG_WriteByte (&sv.signon, ent->v->skin);
1855 for (i=0 ; i<3 ; i++)
1857 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1858 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1861 // throw the entity away now
1865 //=============================================================================
1872 void PF_setspawnparms (void)
1878 ent = G_EDICT(OFS_PARM0);
1879 i = NUM_FOR_EDICT(ent);
1880 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1882 Con_Printf("tried to setspawnparms on a non-client\n");
1886 // copy spawn parms out of the client_t
1887 client = svs.clients + i-1;
1888 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1889 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1897 void PF_changelevel (void)
1901 // make sure we don't issue two changelevels
1902 if (svs.changelevel_issued)
1904 svs.changelevel_issued = true;
1906 s = G_STRING(OFS_PARM0);
1907 Cbuf_AddText (va("changelevel %s\n",s));
1912 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1917 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1922 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1929 Returns a vector of length < 1
1934 void PF_randomvec (void)
1939 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1940 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1941 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1943 while (DotProduct(temp, temp) >= 1);
1944 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1951 Returns a color vector indicating the lighting at the requested point.
1953 (Internal Operation note: actually measures the light beneath the point, just like
1954 the model lighting on the client)
1959 void PF_GetLight (void)
1961 vec3_t ambientcolor, diffusecolor, diffusenormal;
1963 p = G_VECTOR(OFS_PARM0);
1964 VectorClear(ambientcolor);
1965 VectorClear(diffusecolor);
1966 VectorClear(diffusenormal);
1967 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1968 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1969 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1972 #define MAX_QC_CVARS 128
1973 cvar_t qc_cvar[MAX_QC_CVARS];
1976 void PF_registercvar (void)
1980 name = G_STRING(OFS_PARM0);
1981 value = G_STRING(OFS_PARM1);
1982 G_FLOAT(OFS_RETURN) = 0;
1983 // first check to see if it has already been defined
1984 if (Cvar_FindVar (name))
1987 // check for overlap with a command
1988 if (Cmd_Exists (name))
1990 Con_Printf ("PF_registercvar: %s is a command\n", name);
1994 if (currentqc_cvar >= MAX_QC_CVARS)
1995 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1997 // copy the name and value
1998 variable = &qc_cvar[currentqc_cvar++];
1999 variable->name = Z_Malloc (strlen(name)+1);
2000 strcpy (variable->name, name);
2001 variable->string = Z_Malloc (strlen(value)+1);
2002 strcpy (variable->string, value);
2003 variable->value = atof (value);
2005 Cvar_RegisterVariable(variable);
2006 G_FLOAT(OFS_RETURN) = 1; // success
2013 returns the minimum of two supplied floats
2020 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2022 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2023 else if (pr_argc >= 3)
2026 float f = G_FLOAT(OFS_PARM0);
2027 for (i = 1;i < pr_argc;i++)
2028 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2029 f = G_FLOAT((OFS_PARM0+i*3));
2030 G_FLOAT(OFS_RETURN) = f;
2033 Host_Error("min: must supply at least 2 floats\n");
2040 returns the maximum of two supplied floats
2047 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2049 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2050 else if (pr_argc >= 3)
2053 float f = G_FLOAT(OFS_PARM0);
2054 for (i = 1;i < pr_argc;i++)
2055 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2056 f = G_FLOAT((OFS_PARM0+i*3));
2057 G_FLOAT(OFS_RETURN) = f;
2060 Host_Error("max: must supply at least 2 floats\n");
2067 returns number bounded by supplied range
2069 min(min, value, max)
2072 void PF_bound (void)
2074 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2081 returns a raised to power b
2088 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2095 copies data from one entity to another
2097 copyentity(src, dst)
2100 void PF_copyentity (void)
2103 in = G_EDICT(OFS_PARM0);
2104 if (in == sv.edicts)
2105 Host_Error("copyentity: can not read world entity\n");
2107 Host_Error("copyentity: can not read free entity\n");
2108 out = G_EDICT(OFS_PARM1);
2109 if (out == sv.edicts)
2110 Host_Error("copyentity: can not modify world entity\n");
2112 Host_Error("copyentity: can not modify free entity\n");
2113 memcpy(out->v, in->v, progs->entityfields * 4);
2120 sets the color of a client and broadcasts the update to all connected clients
2122 setcolor(clientent, value)
2125 void PF_setcolor (void)
2131 entnum = G_EDICTNUM(OFS_PARM0);
2132 i = G_FLOAT(OFS_PARM1);
2134 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2136 Con_Printf ("tried to setcolor a non-client\n");
2140 client = svs.clients + entnum-1;
2141 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2144 client->old_colors = i;
2145 client->edict->v->team = (i & 15) + 1;
2147 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2148 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2149 MSG_WriteByte (&sv.reliable_datagram, i);
2156 effect(origin, modelname, startframe, framecount, framerate)
2159 void PF_effect (void)
2162 s = G_STRING(OFS_PARM1);
2164 Host_Error("effect: no model specified\n");
2166 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2169 void PF_te_blood (void)
2171 if (G_FLOAT(OFS_PARM2) < 1)
2173 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2174 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2176 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2180 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2181 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2182 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2184 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2187 void PF_te_bloodshower (void)
2189 if (G_FLOAT(OFS_PARM3) < 1)
2191 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2192 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2194 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2195 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2196 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2198 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2199 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2200 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2202 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2204 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2207 void PF_te_explosionrgb (void)
2209 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2210 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2213 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2216 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2217 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2218 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2221 void PF_te_particlecube (void)
2223 if (G_FLOAT(OFS_PARM3) < 1)
2225 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2226 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2228 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2232 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2237 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2240 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2242 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2243 // gravity true/false
2244 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2246 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2249 void PF_te_particlerain (void)
2251 if (G_FLOAT(OFS_PARM3) < 1)
2253 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2254 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2256 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2257 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2258 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2260 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2261 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2262 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2264 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2266 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2268 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2270 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2273 void PF_te_particlesnow (void)
2275 if (G_FLOAT(OFS_PARM3) < 1)
2277 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
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]);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2286 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2288 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2289 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2290 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2292 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2294 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2297 void PF_te_spark (void)
2299 if (G_FLOAT(OFS_PARM2) < 1)
2301 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2302 MSG_WriteByte(&sv.datagram, TE_SPARK);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2306 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2308 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2309 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2310 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2312 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2315 void PF_te_gunshotquad (void)
2317 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2318 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
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_spikequad (void)
2327 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2328 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2330 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2331 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2332 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2335 void PF_te_superspikequad (void)
2337 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2338 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2340 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2341 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2342 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2345 void PF_te_explosionquad (void)
2347 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
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_smallflash (void)
2357 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2358 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
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_customflash (void)
2367 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2369 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2370 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2376 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2378 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2380 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2381 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2382 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2385 void PF_te_gunshot (void)
2387 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2388 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
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_spike (void)
2397 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2398 MSG_WriteByte(&sv.datagram, TE_SPIKE);
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_superspike (void)
2407 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2408 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
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_explosion (void)
2417 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
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_tarexplosion (void)
2427 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2428 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
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_wizspike (void)
2437 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2438 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
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]);
2445 void PF_te_knightspike (void)
2447 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2448 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2451 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2452 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2455 void PF_te_lavasplash (void)
2457 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2458 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2465 void PF_te_teleport (void)
2467 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2468 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2470 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2472 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2475 void PF_te_explosion2 (void)
2477 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2478 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2484 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2487 void PF_te_lightning1 (void)
2489 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2490 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2492 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2499 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2503 void PF_te_lightning2 (void)
2505 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2506 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2508 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2510 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2511 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2512 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2514 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2515 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2516 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2519 void PF_te_lightning3 (void)
2521 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2522 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2524 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2526 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2527 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2528 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2530 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2531 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2532 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2535 void PF_te_beam (void)
2537 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2538 MSG_WriteByte(&sv.datagram, TE_BEAM);
2540 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2542 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2543 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2544 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2546 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2547 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2548 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2551 void PF_te_plasmaburn (void)
2553 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2554 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2555 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2556 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2557 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2560 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2563 vec3_t v1, clipplanenormal, normal;
2564 vec_t clipplanedist, clipdist;
2566 if (surf->flags & SURF_PLANEBACK)
2567 VectorNegate(surf->plane->normal, normal);
2569 VectorCopy(surf->plane->normal, normal);
2570 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2572 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2573 VectorNormalizeFast(v1);
2574 CrossProduct(v1, normal, clipplanenormal);
2575 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2576 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2579 clipdist = -clipdist;
2580 VectorMA(out, clipdist, clipplanenormal, out);
2585 static msurface_t *getsurface(edict_t *ed, int surfnum)
2589 if (!ed || ed->e->free)
2591 modelindex = ed->v->modelindex;
2592 if (modelindex < 1 || modelindex >= MAX_MODELS)
2594 model = sv.models[modelindex];
2595 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2597 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2601 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2602 void PF_getsurfacenumpoints(void)
2605 // return 0 if no such surface
2606 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2608 G_FLOAT(OFS_RETURN) = 0;
2612 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2614 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2615 void PF_getsurfacepoint(void)
2620 VectorClear(G_VECTOR(OFS_RETURN));
2621 ed = G_EDICT(OFS_PARM0);
2622 if (!ed || ed->e->free)
2624 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2626 pointnum = G_FLOAT(OFS_PARM2);
2627 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2629 // FIXME: implement rotation/scaling
2630 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2632 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2633 void PF_getsurfacenormal(void)
2636 VectorClear(G_VECTOR(OFS_RETURN));
2637 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2639 // FIXME: implement rotation/scaling
2640 if (surf->flags & SURF_PLANEBACK)
2641 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2643 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2645 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2646 void PF_getsurfacetexture(void)
2649 G_INT(OFS_RETURN) = 0;
2650 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2652 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2654 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2655 void PF_getsurfacenearpoint(void)
2657 int surfnum, best, modelindex;
2659 vec_t dist, bestdist;
2664 G_FLOAT(OFS_RETURN) = -1;
2665 ed = G_EDICT(OFS_PARM0);
2666 point = G_VECTOR(OFS_PARM1);
2668 if (!ed || ed->e->free)
2670 modelindex = ed->v->modelindex;
2671 if (modelindex < 1 || modelindex >= MAX_MODELS)
2673 model = sv.models[modelindex];
2674 if (!model->brushq1.numsurfaces)
2677 // FIXME: implement rotation/scaling
2678 VectorSubtract(point, ed->v->origin, p);
2680 bestdist = 1000000000;
2681 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2683 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2684 dist = PlaneDiff(p, surf->plane);
2686 if (dist < bestdist)
2688 clippointtosurface(surf, p, clipped);
2689 VectorSubtract(clipped, p, clipped);
2690 dist += DotProduct(clipped, clipped);
2691 if (dist < bestdist)
2698 G_FLOAT(OFS_RETURN) = best;
2700 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2701 void PF_getsurfaceclippedpoint(void)
2706 VectorClear(G_VECTOR(OFS_RETURN));
2707 ed = G_EDICT(OFS_PARM0);
2708 if (!ed || ed->e->free)
2710 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2712 // FIXME: implement rotation/scaling
2713 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2714 clippointtosurface(surf, p, out);
2715 // FIXME: implement rotation/scaling
2716 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2719 #define MAX_PRFILES 256
2721 qfile_t *pr_files[MAX_PRFILES];
2723 void PR_Files_Init(void)
2725 memset(pr_files, 0, sizeof(pr_files));
2728 void PR_Files_CloseAll(void)
2731 for (i = 0;i < MAX_PRFILES;i++)
2734 FS_Close(pr_files[i]);
2739 //float(string s) stof = #81; // get numerical value from a string
2742 char string[STRINGTEMP_LENGTH];
2743 PF_VarString(0, string, sizeof(string));
2744 G_FLOAT(OFS_RETURN) = atof(string);
2747 //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
2751 char *modestring, *filename;
2752 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2753 if (pr_files[filenum] == NULL)
2755 if (filenum >= MAX_PRFILES)
2757 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2758 G_FLOAT(OFS_RETURN) = -2;
2761 mode = G_FLOAT(OFS_PARM1);
2764 case 0: // FILE_READ
2767 case 1: // FILE_APPEND
2770 case 2: // FILE_WRITE
2774 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2775 G_FLOAT(OFS_RETURN) = -3;
2778 filename = G_STRING(OFS_PARM0);
2779 // .. is parent directory on many platforms
2780 // / is parent directory on Amiga
2781 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2782 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2783 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2785 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2786 G_FLOAT(OFS_RETURN) = -4;
2789 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2790 if (pr_files[filenum] == NULL)
2791 G_FLOAT(OFS_RETURN) = -1;
2793 G_FLOAT(OFS_RETURN) = filenum;
2796 //void(float fhandle) fclose = #111; // closes a file
2797 void PF_fclose(void)
2799 int filenum = G_FLOAT(OFS_PARM0);
2800 if (filenum < 0 || filenum >= MAX_PRFILES)
2802 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2805 if (pr_files[filenum] == NULL)
2807 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2810 FS_Close(pr_files[filenum]);
2811 pr_files[filenum] = NULL;
2814 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2818 static char string[STRINGTEMP_LENGTH];
2819 int filenum = G_FLOAT(OFS_PARM0);
2820 if (filenum < 0 || filenum >= MAX_PRFILES)
2822 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2825 if (pr_files[filenum] == NULL)
2827 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2833 c = FS_Getc(pr_files[filenum]);
2834 if (c == '\r' || c == '\n' || c < 0)
2836 if (end < STRINGTEMP_LENGTH - 1)
2840 // remove \n following \r
2842 c = FS_Getc(pr_files[filenum]);
2843 if (developer.integer)
2844 Con_Printf("fgets: %s\n", string);
2846 G_INT(OFS_RETURN) = PR_SetString(string);
2848 G_INT(OFS_RETURN) = 0;
2851 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2855 char string[STRINGTEMP_LENGTH];
2856 int filenum = G_FLOAT(OFS_PARM0);
2857 if (filenum < 0 || filenum >= MAX_PRFILES)
2859 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2862 if (pr_files[filenum] == NULL)
2864 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2867 PF_VarString(1, string, sizeof(string));
2868 if ((stringlength = strlen(string)))
2869 FS_Write(pr_files[filenum], string, stringlength);
2870 if (developer.integer)
2871 Con_Printf("fputs: %s\n", string);
2874 //float(string s) strlen = #114; // returns how many characters are in a string
2875 void PF_strlen(void)
2878 s = G_STRING(OFS_PARM0);
2880 G_FLOAT(OFS_RETURN) = strlen(s);
2882 G_FLOAT(OFS_RETURN) = 0;
2885 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2886 void PF_strcat(void)
2888 char *s = PR_GetTempString();
2889 PF_VarString(0, s, STRINGTEMP_LENGTH);
2890 G_INT(OFS_RETURN) = PR_SetString(s);
2893 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2894 void PF_substring(void)
2896 int i, start, length;
2897 char *s, *string = PR_GetTempString();
2898 s = G_STRING(OFS_PARM0);
2899 start = G_FLOAT(OFS_PARM1);
2900 length = G_FLOAT(OFS_PARM2);
2903 for (i = 0;i < start && *s;i++, s++);
2904 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2907 G_INT(OFS_RETURN) = PR_SetString(string);
2910 //vector(string s) stov = #117; // returns vector value from a string
2913 char string[STRINGTEMP_LENGTH];
2914 PF_VarString(0, string, sizeof(string));
2915 Math_atov(string, G_VECTOR(OFS_RETURN));
2918 //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)
2919 void PF_strzone(void)
2922 in = G_STRING(OFS_PARM0);
2923 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2925 G_INT(OFS_RETURN) = PR_SetString(out);
2928 //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!!!)
2929 void PF_strunzone(void)
2931 Mem_Free(G_STRING(OFS_PARM0));
2934 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2935 //this function originally written by KrimZon, made shorter by LordHavoc
2936 void PF_clientcommand (void)
2938 client_t *temp_client;
2941 //find client for this entity
2942 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2943 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2945 Con_Printf("PF_clientcommand: entity is not a client");
2949 temp_client = host_client;
2950 host_client = svs.clients + i;
2951 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2952 host_client = temp_client;
2955 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2956 //this function originally written by KrimZon, made shorter by LordHavoc
2957 char **tokens = NULL;
2958 int max_tokens, num_tokens = 0;
2959 void PF_tokenize (void)
2963 str = G_STRING(OFS_PARM0);
2968 for (i=0;i<num_tokens;i++)
2974 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2975 max_tokens = strlen(str);
2977 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2979 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2980 strcpy(tokens[num_tokens], com_token);
2983 G_FLOAT(OFS_RETURN) = num_tokens;
2986 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2987 //this function originally written by KrimZon, made shorter by LordHavoc
2990 int token_num = G_FLOAT(OFS_PARM0);
2991 if (token_num >= 0 && token_num < num_tokens)
2992 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2994 G_INT(OFS_RETURN) = PR_SetString("");
2997 //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)
2998 void PF_setattachment (void)
3000 edict_t *e = G_EDICT(OFS_PARM0);
3001 edict_t *tagentity = G_EDICT(OFS_PARM1);
3002 char *tagname = G_STRING(OFS_PARM2);
3008 Host_Error("setattachment: can not modify world entity\n");
3010 Host_Error("setattachment: can not modify free entity\n");
3012 if (tagentity == NULL)
3013 tagentity = sv.edicts;
3015 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3017 v->edict = EDICT_TO_PROG(tagentity);
3019 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3022 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3024 modelindex = (int)tagentity->v->modelindex;
3025 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3027 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3028 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3029 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3031 if (v->_float == 0 && model->alias.aliasnum_tags)
3032 for (i = 0;i < model->alias.aliasnum_tags;i++)
3033 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3036 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);
3039 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));
3044 builtin_t pr_builtin[] =
3047 PF_makevectors, // #1 void(entity e) makevectors
3048 PF_setorigin, // #2 void(entity e, vector o) setorigin
3049 PF_setmodel, // #3 void(entity e, string m) setmodel
3050 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3051 NULL, // #5 void(entity e, vector min, vector max) setabssize
3052 PF_break, // #6 void() break
3053 PF_random, // #7 float() random
3054 PF_sound, // #8 void(entity e, float chan, string samp) sound
3055 PF_normalize, // #9 vector(vector v) normalize
3056 PF_error, // #10 void(string e) error
3057 PF_objerror, // #11 void(string e) objerror
3058 PF_vlen, // #12 float(vector v) vlen
3059 PF_vectoyaw, // #13 float(vector v) vectoyaw
3060 PF_Spawn, // #14 entity() spawn
3061 PF_Remove, // #15 void(entity e) remove
3062 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3063 PF_checkclient, // #17 entity() clientlist
3064 PF_Find, // #18 entity(entity start, .string fld, string match) find
3065 PF_precache_sound, // #19 void(string s) precache_sound
3066 PF_precache_model, // #20 void(string s) precache_model
3067 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3068 PF_findradius, // #22 entity(vector org, float rad) findradius
3069 PF_bprint, // #23 void(string s) bprint
3070 PF_sprint, // #24 void(entity client, string s) sprint
3071 PF_dprint, // #25 void(string s) dprint
3072 PF_ftos, // #26 void(string s) ftos
3073 PF_vtos, // #27 void(string s) vtos
3074 PF_coredump, // #28 void() coredump
3075 PF_traceon, // #29 void() traceon
3076 PF_traceoff, // #30 void() traceoff
3077 PF_eprint, // #31 void(entity e) eprint
3078 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3080 PF_droptofloor, // #34 float() droptofloor
3081 PF_lightstyle, // #35 void(float style, string value) lightstyle
3082 PF_rint, // #36 float(float v) rint
3083 PF_floor, // #37 float(float v) floor
3084 PF_ceil, // #38 float(float v) ceil
3086 PF_checkbottom, // #40 float(entity e) checkbottom
3087 PF_pointcontents , // #41 float(vector v) pointcontents
3089 PF_fabs, // #43 float(float f) fabs
3090 PF_aim, // #44 vector(entity e, float speed) aim
3091 PF_cvar, // #45 float(string s) cvar
3092 PF_localcmd, // #46 void(string s) localcmd
3093 PF_nextent, // #47 entity(entity e) nextent
3094 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3095 PF_changeyaw, // #49 void() ChangeYaw
3097 PF_vectoangles, // #51 vector(vector v) vectoangles
3098 PF_WriteByte, // #52 void(float to, float f) WriteByte
3099 PF_WriteChar, // #53 void(float to, float f) WriteChar
3100 PF_WriteShort, // #54 void(float to, float f) WriteShort
3101 PF_WriteLong, // #55 void(float to, float f) WriteLong
3102 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3103 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3104 PF_WriteString, // #58 void(float to, string s) WriteString
3105 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3106 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3107 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3108 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3109 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3110 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3111 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3113 SV_MoveToGoal, // #67 void(float step) movetogoal
3114 PF_precache_file, // #68 string(string s) precache_file
3115 PF_makestatic, // #69 void(entity e) makestatic
3116 PF_changelevel, // #70 void(string s) changelevel
3118 PF_cvar_set, // #72 void(string var, string val) cvar_set
3119 PF_centerprint, // #73 void(entity client, strings) centerprint
3120 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3121 PF_precache_model, // #75 string(string s) precache_model2
3122 PF_precache_sound, // #76 string(string s) precache_sound2
3123 PF_precache_file, // #77 string(string s) precache_file2
3124 PF_setspawnparms, // #78 void(entity e) setspawnparms
3127 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3136 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3137 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3138 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3139 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3140 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3141 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3142 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3143 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3144 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3145 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3156 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3157 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3158 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3159 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3160 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3161 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3162 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3163 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3164 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3165 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3166 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3167 a a a a a a a a // #120-199
3168 a a a a a a a a a a // #200-299
3169 a a a a a a a a a a // #300-399
3170 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3171 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3172 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3173 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3174 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3175 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3176 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3177 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3178 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3179 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3180 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3181 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3182 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3183 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3184 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3185 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3186 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3187 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3188 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3189 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3190 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3191 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3192 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3193 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3194 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3195 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3196 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3197 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3198 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3199 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3200 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3201 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3202 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3203 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3204 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3205 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3206 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3207 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3208 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3209 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3210 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3211 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3212 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3213 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3220 a a a a a // #450-499 (LordHavoc)
3223 builtin_t *pr_builtins = pr_builtin;
3224 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3226 void PR_Cmd_Init(void)
3228 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3232 void PR_Cmd_Reset(void)
3234 Mem_EmptyPool(pr_strings_mempool);
3235 PR_Files_CloseAll();