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");
1131 Host_Error("remove: tried to remove an entity that was already removed\n");
1136 // entity (entity start, .string field, string match) find = #5;
1144 e = G_EDICTNUM(OFS_PARM0);
1145 f = G_INT(OFS_PARM1);
1146 s = G_STRING(OFS_PARM2);
1149 RETURN_EDICT(sv.edicts);
1153 for (e++ ; e < sv.num_edicts ; e++)
1155 pr_xfunction->builtinsprofile++;
1169 RETURN_EDICT(sv.edicts);
1172 // LordHavoc: added this for searching float, int, and entity reference fields
1173 void PF_FindFloat (void)
1180 e = G_EDICTNUM(OFS_PARM0);
1181 f = G_INT(OFS_PARM1);
1182 s = G_FLOAT(OFS_PARM2);
1184 for (e++ ; e < sv.num_edicts ; e++)
1186 pr_xfunction->builtinsprofile++;
1190 if (E_FLOAT(ed,f) == s)
1197 RETURN_EDICT(sv.edicts);
1200 // chained search for strings in entity fields
1201 // entity(.string field, string match) findchain = #402;
1202 void PF_findchain (void)
1207 edict_t *ent, *chain;
1209 chain = (edict_t *)sv.edicts;
1211 f = G_INT(OFS_PARM0);
1212 s = G_STRING(OFS_PARM1);
1215 RETURN_EDICT(sv.edicts);
1219 ent = NEXT_EDICT(sv.edicts);
1220 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1222 pr_xfunction->builtinsprofile++;
1225 t = E_STRING(ent,f);
1231 ent->v->chain = EDICT_TO_PROG(chain);
1235 RETURN_EDICT(chain);
1238 // LordHavoc: chained search for float, int, and entity reference fields
1239 // entity(.string field, float match) findchainfloat = #403;
1240 void PF_findchainfloat (void)
1245 edict_t *ent, *chain;
1247 chain = (edict_t *)sv.edicts;
1249 f = G_INT(OFS_PARM0);
1250 s = G_FLOAT(OFS_PARM1);
1252 ent = NEXT_EDICT(sv.edicts);
1253 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1255 pr_xfunction->builtinsprofile++;
1258 if (E_FLOAT(ent,f) != s)
1261 ent->v->chain = EDICT_TO_PROG(chain);
1265 RETURN_EDICT(chain);
1268 void PR_CheckEmptyString (char *s)
1271 Host_Error ("Bad string");
1274 void PF_precache_file (void)
1275 { // precache_file is only used to copy files with qcc, it does nothing
1276 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1279 void PF_precache_sound (void)
1284 if (sv.state != ss_loading)
1285 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1287 s = G_STRING(OFS_PARM0);
1288 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1289 PR_CheckEmptyString (s);
1291 for (i=0 ; i<MAX_SOUNDS ; i++)
1293 if (!sv.sound_precache[i])
1295 sv.sound_precache[i] = s;
1298 if (!strcmp(sv.sound_precache[i], s))
1301 Host_Error ("PF_precache_sound: overflow");
1304 void PF_precache_model (void)
1309 if (sv.state != ss_loading)
1310 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1312 s = G_STRING(OFS_PARM0);
1313 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1315 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1316 PR_CheckEmptyString (s);
1318 for (i=0 ; i<MAX_MODELS ; i++)
1320 if (!sv.model_precache[i])
1322 sv.model_precache[i] = s;
1323 sv.models[i] = Mod_ForName (s, true, false, false);
1326 if (!strcmp(sv.model_precache[i], s))
1329 Host_Error ("PF_precache_model: overflow");
1333 void PF_coredump (void)
1338 void PF_traceon (void)
1343 void PF_traceoff (void)
1348 void PF_eprint (void)
1350 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1357 float(float yaw, float dist) walkmove
1360 void PF_walkmove (void)
1368 ent = PROG_TO_EDICT(pr_global_struct->self);
1369 if (ent == sv.edicts)
1370 Host_Error("walkmove: can not modify world entity\n");
1372 Host_Error("walkmove: can not modify free entity\n");
1373 yaw = G_FLOAT(OFS_PARM0);
1374 dist = G_FLOAT(OFS_PARM1);
1376 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1378 G_FLOAT(OFS_RETURN) = 0;
1382 yaw = yaw*M_PI*2 / 360;
1384 move[0] = cos(yaw)*dist;
1385 move[1] = sin(yaw)*dist;
1388 // save program state, because SV_movestep may call other progs
1389 oldf = pr_xfunction;
1390 oldself = pr_global_struct->self;
1392 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1395 // restore program state
1396 pr_xfunction = oldf;
1397 pr_global_struct->self = oldself;
1407 void PF_droptofloor (void)
1413 ent = PROG_TO_EDICT(pr_global_struct->self);
1414 if (ent == sv.edicts)
1415 Host_Error("droptofloor: can not modify world entity\n");
1417 Host_Error("droptofloor: can not modify free entity\n");
1419 VectorCopy (ent->v->origin, end);
1422 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1424 if (trace.fraction == 1)
1425 G_FLOAT(OFS_RETURN) = 0;
1428 VectorCopy (trace.endpos, ent->v->origin);
1429 SV_LinkEdict (ent, false);
1430 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1431 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1432 G_FLOAT(OFS_RETURN) = 1;
1433 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1434 ent->e->suspendedinairflag = true;
1442 void(float style, string value) lightstyle
1445 void PF_lightstyle (void)
1452 style = G_FLOAT(OFS_PARM0);
1453 val = G_STRING(OFS_PARM1);
1455 // change the string in sv
1456 sv.lightstyles[style] = val;
1458 // send message to all clients on this server
1459 if (sv.state != ss_active)
1462 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1464 if (client->netconnection)
1466 MSG_WriteChar (&client->message, svc_lightstyle);
1467 MSG_WriteChar (&client->message,style);
1468 MSG_WriteString (&client->message, val);
1476 f = G_FLOAT(OFS_PARM0);
1478 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1480 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1482 void PF_floor (void)
1484 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1488 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1497 void PF_checkbottom (void)
1499 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1507 void PF_pointcontents (void)
1509 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1516 entity nextent(entity)
1519 void PF_nextent (void)
1524 i = G_EDICTNUM(OFS_PARM0);
1527 pr_xfunction->builtinsprofile++;
1529 if (i == sv.num_edicts)
1531 RETURN_EDICT(sv.edicts);
1547 Pick a vector for the player to shoot along
1548 vector aim(entity, missilespeed)
1553 edict_t *ent, *check, *bestent;
1554 vec3_t start, dir, end, bestdir;
1557 float dist, bestdist;
1560 ent = G_EDICT(OFS_PARM0);
1561 if (ent == sv.edicts)
1562 Host_Error("aim: can not use world entity\n");
1564 Host_Error("aim: can not use free entity\n");
1565 speed = G_FLOAT(OFS_PARM1);
1567 VectorCopy (ent->v->origin, start);
1570 // try sending a trace straight
1571 VectorCopy (pr_global_struct->v_forward, dir);
1572 VectorMA (start, 2048, dir, end);
1573 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1574 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1575 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1577 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1582 // try all possible entities
1583 VectorCopy (dir, bestdir);
1584 bestdist = sv_aim.value;
1587 check = NEXT_EDICT(sv.edicts);
1588 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1590 pr_xfunction->builtinsprofile++;
1591 if (check->v->takedamage != DAMAGE_AIM)
1595 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1596 continue; // don't aim at teammate
1597 for (j=0 ; j<3 ; j++)
1598 end[j] = check->v->origin[j]
1599 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1600 VectorSubtract (end, start, dir);
1601 VectorNormalize (dir);
1602 dist = DotProduct (dir, pr_global_struct->v_forward);
1603 if (dist < bestdist)
1604 continue; // to far to turn
1605 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1606 if (tr.ent == check)
1607 { // can shoot at this one
1615 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1616 dist = DotProduct (dir, pr_global_struct->v_forward);
1617 VectorScale (pr_global_struct->v_forward, dist, end);
1619 VectorNormalize (end);
1620 VectorCopy (end, G_VECTOR(OFS_RETURN));
1624 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1632 This was a major timewaster in progs, so it was converted to C
1635 void PF_changeyaw (void)
1638 float ideal, current, move, speed;
1640 ent = PROG_TO_EDICT(pr_global_struct->self);
1641 if (ent == sv.edicts)
1642 Host_Error("changeyaw: can not modify world entity\n");
1644 Host_Error("changeyaw: can not modify free entity\n");
1645 current = ANGLEMOD(ent->v->angles[1]);
1646 ideal = ent->v->ideal_yaw;
1647 speed = ent->v->yaw_speed;
1649 if (current == ideal)
1651 move = ideal - current;
1652 if (ideal > current)
1673 ent->v->angles[1] = ANGLEMOD (current + move);
1681 void PF_changepitch (void)
1684 float ideal, current, move, speed;
1687 ent = G_EDICT(OFS_PARM0);
1688 if (ent == sv.edicts)
1689 Host_Error("changepitch: can not modify world entity\n");
1691 Host_Error("changepitch: can not modify free entity\n");
1692 current = ANGLEMOD( ent->v->angles[0] );
1693 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1694 ideal = val->_float;
1697 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1700 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1701 speed = val->_float;
1704 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1708 if (current == ideal)
1710 move = ideal - current;
1711 if (ideal > current)
1732 ent->v->angles[0] = ANGLEMOD (current + move);
1736 ===============================================================================
1740 ===============================================================================
1743 #define MSG_BROADCAST 0 // unreliable to all
1744 #define MSG_ONE 1 // reliable to one (msg_entity)
1745 #define MSG_ALL 2 // reliable to all
1746 #define MSG_INIT 3 // write to the init string
1748 sizebuf_t *WriteDest (void)
1754 dest = G_FLOAT(OFS_PARM0);
1758 return &sv.datagram;
1761 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1762 entnum = NUM_FOR_EDICT(ent);
1763 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1764 Host_Error("WriteDest: tried to write to non-client\n");
1765 return &svs.clients[entnum-1].message;
1768 return &sv.reliable_datagram;
1774 Host_Error ("WriteDest: bad destination");
1781 void PF_WriteByte (void)
1783 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1786 void PF_WriteChar (void)
1788 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1791 void PF_WriteShort (void)
1793 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1796 void PF_WriteLong (void)
1798 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1801 void PF_WriteAngle (void)
1803 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1806 void PF_WriteCoord (void)
1808 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1811 void PF_WriteString (void)
1813 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1817 void PF_WriteEntity (void)
1819 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1822 //=============================================================================
1824 void PF_makestatic (void)
1829 ent = G_EDICT(OFS_PARM0);
1830 if (ent == sv.edicts)
1831 Host_Error("makestatic: can not modify world entity\n");
1833 Host_Error("makestatic: can not modify free entity\n");
1836 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1841 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1842 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1843 MSG_WriteShort (&sv.signon, ent->v->frame);
1847 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1848 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1849 MSG_WriteByte (&sv.signon, ent->v->frame);
1852 MSG_WriteByte (&sv.signon, ent->v->colormap);
1853 MSG_WriteByte (&sv.signon, ent->v->skin);
1854 for (i=0 ; i<3 ; i++)
1856 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1857 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1860 // throw the entity away now
1864 //=============================================================================
1871 void PF_setspawnparms (void)
1877 ent = G_EDICT(OFS_PARM0);
1878 i = NUM_FOR_EDICT(ent);
1879 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1881 Con_Printf("tried to setspawnparms on a non-client\n");
1885 // copy spawn parms out of the client_t
1886 client = svs.clients + i-1;
1887 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1888 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1896 void PF_changelevel (void)
1900 // make sure we don't issue two changelevels
1901 if (svs.changelevel_issued)
1903 svs.changelevel_issued = true;
1905 s = G_STRING(OFS_PARM0);
1906 Cbuf_AddText (va("changelevel %s\n",s));
1911 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1916 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1921 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1928 Returns a vector of length < 1
1933 void PF_randomvec (void)
1938 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1939 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1940 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1942 while (DotProduct(temp, temp) >= 1);
1943 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1950 Returns a color vector indicating the lighting at the requested point.
1952 (Internal Operation note: actually measures the light beneath the point, just like
1953 the model lighting on the client)
1958 void PF_GetLight (void)
1960 vec3_t ambientcolor, diffusecolor, diffusenormal;
1962 p = G_VECTOR(OFS_PARM0);
1963 VectorClear(ambientcolor);
1964 VectorClear(diffusecolor);
1965 VectorClear(diffusenormal);
1966 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1967 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1968 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1971 #define MAX_QC_CVARS 128
1972 cvar_t qc_cvar[MAX_QC_CVARS];
1975 void PF_registercvar (void)
1979 name = G_STRING(OFS_PARM0);
1980 value = G_STRING(OFS_PARM1);
1981 G_FLOAT(OFS_RETURN) = 0;
1982 // first check to see if it has already been defined
1983 if (Cvar_FindVar (name))
1986 // check for overlap with a command
1987 if (Cmd_Exists (name))
1989 Con_Printf ("PF_registercvar: %s is a command\n", name);
1993 if (currentqc_cvar >= MAX_QC_CVARS)
1994 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1996 // copy the name and value
1997 variable = &qc_cvar[currentqc_cvar++];
1998 variable->name = Z_Malloc (strlen(name)+1);
1999 strcpy (variable->name, name);
2000 variable->string = Z_Malloc (strlen(value)+1);
2001 strcpy (variable->string, value);
2002 variable->value = atof (value);
2004 Cvar_RegisterVariable(variable);
2005 G_FLOAT(OFS_RETURN) = 1; // success
2012 returns the minimum of two supplied floats
2019 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2021 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2022 else if (pr_argc >= 3)
2025 float f = G_FLOAT(OFS_PARM0);
2026 for (i = 1;i < pr_argc;i++)
2027 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2028 f = G_FLOAT((OFS_PARM0+i*3));
2029 G_FLOAT(OFS_RETURN) = f;
2032 Host_Error("min: must supply at least 2 floats\n");
2039 returns the maximum of two supplied floats
2046 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2048 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2049 else if (pr_argc >= 3)
2052 float f = G_FLOAT(OFS_PARM0);
2053 for (i = 1;i < pr_argc;i++)
2054 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2055 f = G_FLOAT((OFS_PARM0+i*3));
2056 G_FLOAT(OFS_RETURN) = f;
2059 Host_Error("max: must supply at least 2 floats\n");
2066 returns number bounded by supplied range
2068 min(min, value, max)
2071 void PF_bound (void)
2073 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2080 returns a raised to power b
2087 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2094 copies data from one entity to another
2096 copyentity(src, dst)
2099 void PF_copyentity (void)
2102 in = G_EDICT(OFS_PARM0);
2103 if (in == sv.edicts)
2104 Host_Error("copyentity: can not read world entity\n");
2106 Host_Error("copyentity: can not read free entity\n");
2107 out = G_EDICT(OFS_PARM1);
2108 if (out == sv.edicts)
2109 Host_Error("copyentity: can not modify world entity\n");
2111 Host_Error("copyentity: can not modify free entity\n");
2112 memcpy(out->v, in->v, progs->entityfields * 4);
2119 sets the color of a client and broadcasts the update to all connected clients
2121 setcolor(clientent, value)
2124 void PF_setcolor (void)
2130 entnum = G_EDICTNUM(OFS_PARM0);
2131 i = G_FLOAT(OFS_PARM1);
2133 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2135 Con_Printf ("tried to setcolor a non-client\n");
2139 client = svs.clients + entnum-1;
2140 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2143 client->old_colors = i;
2144 client->edict->v->team = (i & 15) + 1;
2146 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2147 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2148 MSG_WriteByte (&sv.reliable_datagram, i);
2155 effect(origin, modelname, startframe, framecount, framerate)
2158 void PF_effect (void)
2161 s = G_STRING(OFS_PARM1);
2163 Host_Error("effect: no model specified\n");
2165 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2168 void PF_te_blood (void)
2170 if (G_FLOAT(OFS_PARM2) < 1)
2172 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2173 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2175 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2176 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2179 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2180 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2181 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2183 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2186 void PF_te_bloodshower (void)
2188 if (G_FLOAT(OFS_PARM3) < 1)
2190 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2191 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2193 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2194 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2195 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2197 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2198 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2199 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2201 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2203 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2206 void PF_te_explosionrgb (void)
2208 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2209 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2213 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2215 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2216 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2217 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2220 void PF_te_particlecube (void)
2222 if (G_FLOAT(OFS_PARM3) < 1)
2224 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2225 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2227 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2228 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2231 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2232 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2237 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2239 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2241 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2242 // gravity true/false
2243 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2245 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2248 void PF_te_particlerain (void)
2250 if (G_FLOAT(OFS_PARM3) < 1)
2252 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2253 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2255 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2256 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2257 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2259 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2260 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2261 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2263 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2264 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2267 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2269 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2272 void PF_te_particlesnow (void)
2274 if (G_FLOAT(OFS_PARM3) < 1)
2276 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2277 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2279 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2280 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2281 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2287 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2288 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2289 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2291 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2293 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2296 void PF_te_spark (void)
2298 if (G_FLOAT(OFS_PARM2) < 1)
2300 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2301 MSG_WriteByte(&sv.datagram, TE_SPARK);
2303 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2307 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2308 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2309 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2311 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2314 void PF_te_gunshotquad (void)
2316 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2317 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2319 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2320 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2321 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2324 void PF_te_spikequad (void)
2326 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2327 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2329 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2330 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2331 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2334 void PF_te_superspikequad (void)
2336 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2337 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2339 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2340 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2341 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2344 void PF_te_explosionquad (void)
2346 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2347 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2349 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2350 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2351 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2354 void PF_te_smallflash (void)
2356 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2357 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2359 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2360 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2361 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2364 void PF_te_customflash (void)
2366 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2368 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2369 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2371 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2372 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2375 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2377 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2379 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2380 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2381 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2384 void PF_te_gunshot (void)
2386 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2387 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2389 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2390 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2391 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2394 void PF_te_spike (void)
2396 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2399 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2400 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2401 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2404 void PF_te_superspike (void)
2406 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2407 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2409 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2410 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2411 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2414 void PF_te_explosion (void)
2416 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2417 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2419 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2420 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2421 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2424 void PF_te_tarexplosion (void)
2426 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2427 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2429 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2430 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2431 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2434 void PF_te_wizspike (void)
2436 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2437 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2439 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2440 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2441 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2444 void PF_te_knightspike (void)
2446 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2447 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2451 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2454 void PF_te_lavasplash (void)
2456 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2457 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2464 void PF_te_teleport (void)
2466 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2467 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2469 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2470 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2474 void PF_te_explosion2 (void)
2476 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2477 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2479 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2483 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2486 void PF_te_lightning1 (void)
2488 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2489 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2491 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2499 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2502 void PF_te_lightning2 (void)
2504 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2505 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2507 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2509 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2510 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2511 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2513 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2514 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2515 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2518 void PF_te_lightning3 (void)
2520 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2521 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2523 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2525 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2526 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2527 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2529 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2530 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2531 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2534 void PF_te_beam (void)
2536 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2537 MSG_WriteByte(&sv.datagram, TE_BEAM);
2539 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2541 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2542 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2543 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2545 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2546 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2547 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2550 void PF_te_plasmaburn (void)
2552 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2553 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2554 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2555 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2556 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2559 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2562 vec3_t v1, clipplanenormal, normal;
2563 vec_t clipplanedist, clipdist;
2565 if (surf->flags & SURF_PLANEBACK)
2566 VectorNegate(surf->plane->normal, normal);
2568 VectorCopy(surf->plane->normal, normal);
2569 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2571 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2572 VectorNormalizeFast(v1);
2573 CrossProduct(v1, normal, clipplanenormal);
2574 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2575 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2578 clipdist = -clipdist;
2579 VectorMA(out, clipdist, clipplanenormal, out);
2584 static msurface_t *getsurface(edict_t *ed, int surfnum)
2588 if (!ed || ed->e->free)
2590 modelindex = ed->v->modelindex;
2591 if (modelindex < 1 || modelindex >= MAX_MODELS)
2593 model = sv.models[modelindex];
2594 if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces)
2596 return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2600 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2601 void PF_getsurfacenumpoints(void)
2604 // return 0 if no such surface
2605 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2607 G_FLOAT(OFS_RETURN) = 0;
2611 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2613 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2614 void PF_getsurfacepoint(void)
2619 VectorClear(G_VECTOR(OFS_RETURN));
2620 ed = G_EDICT(OFS_PARM0);
2621 if (!ed || ed->e->free)
2623 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2625 pointnum = G_FLOAT(OFS_PARM2);
2626 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2628 // FIXME: implement rotation/scaling
2629 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2631 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2632 void PF_getsurfacenormal(void)
2635 VectorClear(G_VECTOR(OFS_RETURN));
2636 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2638 // FIXME: implement rotation/scaling
2639 if (surf->flags & SURF_PLANEBACK)
2640 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2642 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2644 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2645 void PF_getsurfacetexture(void)
2648 G_INT(OFS_RETURN) = 0;
2649 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2651 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2653 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2654 void PF_getsurfacenearpoint(void)
2656 int surfnum, best, modelindex;
2658 vec_t dist, bestdist;
2663 G_FLOAT(OFS_RETURN) = -1;
2664 ed = G_EDICT(OFS_PARM0);
2665 point = G_VECTOR(OFS_PARM1);
2667 if (!ed || ed->e->free)
2669 modelindex = ed->v->modelindex;
2670 if (modelindex < 1 || modelindex >= MAX_MODELS)
2672 model = sv.models[modelindex];
2673 if (!model->brushq1.numsurfaces)
2676 // FIXME: implement rotation/scaling
2677 VectorSubtract(point, ed->v->origin, p);
2679 bestdist = 1000000000;
2680 for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++)
2682 surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface;
2683 dist = PlaneDiff(p, surf->plane);
2685 if (dist < bestdist)
2687 clippointtosurface(surf, p, clipped);
2688 VectorSubtract(clipped, p, clipped);
2689 dist += DotProduct(clipped, clipped);
2690 if (dist < bestdist)
2697 G_FLOAT(OFS_RETURN) = best;
2699 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2700 void PF_getsurfaceclippedpoint(void)
2705 VectorClear(G_VECTOR(OFS_RETURN));
2706 ed = G_EDICT(OFS_PARM0);
2707 if (!ed || ed->e->free)
2709 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2711 // FIXME: implement rotation/scaling
2712 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2713 clippointtosurface(surf, p, out);
2714 // FIXME: implement rotation/scaling
2715 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2718 #define MAX_PRFILES 256
2720 qfile_t *pr_files[MAX_PRFILES];
2722 void PR_Files_Init(void)
2724 memset(pr_files, 0, sizeof(pr_files));
2727 void PR_Files_CloseAll(void)
2730 for (i = 0;i < MAX_PRFILES;i++)
2733 FS_Close(pr_files[i]);
2738 //float(string s) stof = #81; // get numerical value from a string
2741 char string[STRINGTEMP_LENGTH];
2742 PF_VarString(0, string, sizeof(string));
2743 G_FLOAT(OFS_RETURN) = atof(string);
2746 //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
2750 char *modestring, *filename;
2751 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2752 if (pr_files[filenum] == NULL)
2754 if (filenum >= MAX_PRFILES)
2756 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2757 G_FLOAT(OFS_RETURN) = -2;
2760 mode = G_FLOAT(OFS_PARM1);
2763 case 0: // FILE_READ
2766 case 1: // FILE_APPEND
2769 case 2: // FILE_WRITE
2773 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2774 G_FLOAT(OFS_RETURN) = -3;
2777 filename = G_STRING(OFS_PARM0);
2778 // .. is parent directory on many platforms
2779 // / is parent directory on Amiga
2780 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2781 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2782 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2784 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2785 G_FLOAT(OFS_RETURN) = -4;
2788 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2789 if (pr_files[filenum] == NULL)
2790 G_FLOAT(OFS_RETURN) = -1;
2792 G_FLOAT(OFS_RETURN) = filenum;
2795 //void(float fhandle) fclose = #111; // closes a file
2796 void PF_fclose(void)
2798 int filenum = G_FLOAT(OFS_PARM0);
2799 if (filenum < 0 || filenum >= MAX_PRFILES)
2801 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2804 if (pr_files[filenum] == NULL)
2806 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2809 FS_Close(pr_files[filenum]);
2810 pr_files[filenum] = NULL;
2813 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2817 static char string[STRINGTEMP_LENGTH];
2818 int filenum = G_FLOAT(OFS_PARM0);
2819 if (filenum < 0 || filenum >= MAX_PRFILES)
2821 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2824 if (pr_files[filenum] == NULL)
2826 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2832 c = FS_Getc(pr_files[filenum]);
2833 if (c == '\r' || c == '\n' || c < 0)
2835 if (end < STRINGTEMP_LENGTH - 1)
2839 // remove \n following \r
2841 c = FS_Getc(pr_files[filenum]);
2842 if (developer.integer)
2843 Con_Printf("fgets: %s\n", string);
2845 G_INT(OFS_RETURN) = PR_SetString(string);
2847 G_INT(OFS_RETURN) = 0;
2850 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2854 char string[STRINGTEMP_LENGTH];
2855 int filenum = G_FLOAT(OFS_PARM0);
2856 if (filenum < 0 || filenum >= MAX_PRFILES)
2858 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2861 if (pr_files[filenum] == NULL)
2863 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2866 PF_VarString(1, string, sizeof(string));
2867 if ((stringlength = strlen(string)))
2868 FS_Write(pr_files[filenum], string, stringlength);
2869 if (developer.integer)
2870 Con_Printf("fputs: %s\n", string);
2873 //float(string s) strlen = #114; // returns how many characters are in a string
2874 void PF_strlen(void)
2877 s = G_STRING(OFS_PARM0);
2879 G_FLOAT(OFS_RETURN) = strlen(s);
2881 G_FLOAT(OFS_RETURN) = 0;
2884 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2885 void PF_strcat(void)
2887 char *s = PR_GetTempString();
2888 PF_VarString(0, s, STRINGTEMP_LENGTH);
2889 G_INT(OFS_RETURN) = PR_SetString(s);
2892 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2893 void PF_substring(void)
2895 int i, start, length;
2896 char *s, *string = PR_GetTempString();
2897 s = G_STRING(OFS_PARM0);
2898 start = G_FLOAT(OFS_PARM1);
2899 length = G_FLOAT(OFS_PARM2);
2902 for (i = 0;i < start && *s;i++, s++);
2903 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2906 G_INT(OFS_RETURN) = PR_SetString(string);
2909 //vector(string s) stov = #117; // returns vector value from a string
2912 char string[STRINGTEMP_LENGTH];
2913 PF_VarString(0, string, sizeof(string));
2914 Math_atov(string, G_VECTOR(OFS_RETURN));
2917 //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)
2918 void PF_strzone(void)
2921 in = G_STRING(OFS_PARM0);
2922 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2924 G_INT(OFS_RETURN) = PR_SetString(out);
2927 //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!!!)
2928 void PF_strunzone(void)
2930 Mem_Free(G_STRING(OFS_PARM0));
2933 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2934 //this function originally written by KrimZon, made shorter by LordHavoc
2935 void PF_clientcommand (void)
2937 client_t *temp_client;
2940 //find client for this entity
2941 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2942 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2944 Con_Printf("PF_clientcommand: entity is not a client");
2948 temp_client = host_client;
2949 host_client = svs.clients + i;
2950 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2951 host_client = temp_client;
2954 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2955 //this function originally written by KrimZon, made shorter by LordHavoc
2956 char **tokens = NULL;
2957 int max_tokens, num_tokens = 0;
2958 void PF_tokenize (void)
2962 str = G_STRING(OFS_PARM0);
2967 for (i=0;i<num_tokens;i++)
2973 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2974 max_tokens = strlen(str);
2976 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2978 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2979 strcpy(tokens[num_tokens], com_token);
2982 G_FLOAT(OFS_RETURN) = num_tokens;
2985 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2986 //this function originally written by KrimZon, made shorter by LordHavoc
2989 int token_num = G_FLOAT(OFS_PARM0);
2990 if (token_num >= 0 && token_num < num_tokens)
2991 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
2993 G_INT(OFS_RETURN) = PR_SetString("");
2996 //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)
2997 void PF_setattachment (void)
2999 edict_t *e = G_EDICT(OFS_PARM0);
3000 edict_t *tagentity = G_EDICT(OFS_PARM1);
3001 char *tagname = G_STRING(OFS_PARM2);
3007 Host_Error("setattachment: can not modify world entity\n");
3009 Host_Error("setattachment: can not modify free entity\n");
3011 if (tagentity == NULL)
3012 tagentity = sv.edicts;
3014 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3016 v->edict = EDICT_TO_PROG(tagentity);
3018 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3021 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3023 modelindex = (int)tagentity->v->modelindex;
3024 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3026 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3027 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3028 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3030 if (v->_float == 0 && model->alias.aliasnum_tags)
3031 for (i = 0;i < model->alias.aliasnum_tags;i++)
3032 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3035 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);
3038 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));
3043 builtin_t pr_builtin[] =
3046 PF_makevectors, // #1 void(entity e) makevectors
3047 PF_setorigin, // #2 void(entity e, vector o) setorigin
3048 PF_setmodel, // #3 void(entity e, string m) setmodel
3049 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3050 NULL, // #5 void(entity e, vector min, vector max) setabssize
3051 PF_break, // #6 void() break
3052 PF_random, // #7 float() random
3053 PF_sound, // #8 void(entity e, float chan, string samp) sound
3054 PF_normalize, // #9 vector(vector v) normalize
3055 PF_error, // #10 void(string e) error
3056 PF_objerror, // #11 void(string e) objerror
3057 PF_vlen, // #12 float(vector v) vlen
3058 PF_vectoyaw, // #13 float(vector v) vectoyaw
3059 PF_Spawn, // #14 entity() spawn
3060 PF_Remove, // #15 void(entity e) remove
3061 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3062 PF_checkclient, // #17 entity() clientlist
3063 PF_Find, // #18 entity(entity start, .string fld, string match) find
3064 PF_precache_sound, // #19 void(string s) precache_sound
3065 PF_precache_model, // #20 void(string s) precache_model
3066 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3067 PF_findradius, // #22 entity(vector org, float rad) findradius
3068 PF_bprint, // #23 void(string s) bprint
3069 PF_sprint, // #24 void(entity client, string s) sprint
3070 PF_dprint, // #25 void(string s) dprint
3071 PF_ftos, // #26 void(string s) ftos
3072 PF_vtos, // #27 void(string s) vtos
3073 PF_coredump, // #28 void() coredump
3074 PF_traceon, // #29 void() traceon
3075 PF_traceoff, // #30 void() traceoff
3076 PF_eprint, // #31 void(entity e) eprint
3077 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3079 PF_droptofloor, // #34 float() droptofloor
3080 PF_lightstyle, // #35 void(float style, string value) lightstyle
3081 PF_rint, // #36 float(float v) rint
3082 PF_floor, // #37 float(float v) floor
3083 PF_ceil, // #38 float(float v) ceil
3085 PF_checkbottom, // #40 float(entity e) checkbottom
3086 PF_pointcontents , // #41 float(vector v) pointcontents
3088 PF_fabs, // #43 float(float f) fabs
3089 PF_aim, // #44 vector(entity e, float speed) aim
3090 PF_cvar, // #45 float(string s) cvar
3091 PF_localcmd, // #46 void(string s) localcmd
3092 PF_nextent, // #47 entity(entity e) nextent
3093 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3094 PF_changeyaw, // #49 void() ChangeYaw
3096 PF_vectoangles, // #51 vector(vector v) vectoangles
3097 PF_WriteByte, // #52 void(float to, float f) WriteByte
3098 PF_WriteChar, // #53 void(float to, float f) WriteChar
3099 PF_WriteShort, // #54 void(float to, float f) WriteShort
3100 PF_WriteLong, // #55 void(float to, float f) WriteLong
3101 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3102 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3103 PF_WriteString, // #58 void(float to, string s) WriteString
3104 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3105 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3106 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3107 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3108 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3109 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3110 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3112 SV_MoveToGoal, // #67 void(float step) movetogoal
3113 PF_precache_file, // #68 string(string s) precache_file
3114 PF_makestatic, // #69 void(entity e) makestatic
3115 PF_changelevel, // #70 void(string s) changelevel
3117 PF_cvar_set, // #72 void(string var, string val) cvar_set
3118 PF_centerprint, // #73 void(entity client, strings) centerprint
3119 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3120 PF_precache_model, // #75 string(string s) precache_model2
3121 PF_precache_sound, // #76 string(string s) precache_sound2
3122 PF_precache_file, // #77 string(string s) precache_file2
3123 PF_setspawnparms, // #78 void(entity e) setspawnparms
3126 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3135 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3136 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3137 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3138 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3139 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3140 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3141 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3142 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3143 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3144 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3155 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3156 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3157 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3158 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3159 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3160 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3161 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3162 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3163 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3164 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3165 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3166 a a a a a a a a // #120-199
3167 a a a a a a a a a a // #200-299
3168 a a a a a a a a a a // #300-399
3169 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3170 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3171 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3172 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3173 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3174 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3175 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3176 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3177 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3178 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3179 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3180 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3181 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3182 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3183 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3184 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3185 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3186 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3187 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3188 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3189 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3190 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3191 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3192 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3193 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3194 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3195 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3196 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3197 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3198 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3199 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3200 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3201 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3202 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3203 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3204 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3205 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3206 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3207 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3208 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3209 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3210 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3211 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3212 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3219 a a a a a // #450-499 (LordHavoc)
3222 builtin_t *pr_builtins = pr_builtin;
3223 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3225 void PR_Cmd_Init(void)
3227 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3231 void PR_Cmd_Reset(void)
3233 Mem_EmptyPool(pr_strings_mempool);
3234 PR_Files_CloseAll();