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) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
43 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
44 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
48 ===============================================================================
52 ===============================================================================
56 void PF_VarString(int first, char *out, int outlength)
62 outend = out + outlength - 1;
63 for (i = first;i < pr_argc && out < outend;i++)
65 s = G_STRING((OFS_PARM0+i*3));
66 while (out < outend && *s)
72 char *ENGINE_EXTENSIONS =
83 "DP_ENT_CUSTOMCOLORMAP "
84 "DP_ENT_EXTERIORMODELTOCLIENT "
86 "DP_ENT_LOWPRECISION "
89 "DP_GFX_EXTERNALTEXTURES "
91 "DP_GFX_QUAKE3MODELTAGS "
95 "DP_HALFLIFE_MAP_CVAR "
99 "DP_MOVETYPEBOUNCEMISSILE "
106 "DP_QC_FINDCHAINFLOAT "
108 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
112 "DP_QC_MULTIPLETEMPSTRINGS "
114 "DP_QC_SINCOSSQRTPOW "
117 "DP_QC_TRACE_MOVETYPE_HITMODEL "
118 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
119 "DP_QC_VECTORVECTORS "
123 "DP_SND_DIRECTIONLESSATTNNONE "
128 "DP_SV_DRAWONLYTOCLIENT "
130 "DP_SV_EXTERIORMODELTOCLIENT "
131 "DP_SV_NODRAWTOCLIENT "
132 "DP_SV_PLAYERPHYSICS "
133 "DP_SV_ROTATINGBMODEL "
139 "DP_TE_EXPLOSIONRGB "
141 "DP_TE_PARTICLECUBE "
142 "DP_TE_PARTICLERAIN "
143 "DP_TE_PARTICLESNOW "
145 "DP_TE_QUADEFFECTS1 "
148 "DP_TE_STANDARDEFFECTBUILTINS "
151 "KRIMZON_SV_PARSECLIENTCOMMAND "
154 "TENEBRAE_GFX_DLIGHTS "
158 qboolean checkextension(char *name)
163 for (e = ENGINE_EXTENSIONS;*e;e++)
170 while (*e && *e != ' ')
172 if (e - start == len)
173 if (!strncasecmp(start, name, len))
183 returns true if the extension is supported by the server
185 checkextension(extensionname)
188 void PF_checkextension (void)
190 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
197 This is a TERMINAL error, which will kill off the entire server.
206 char string[STRINGTEMP_LENGTH];
208 PF_VarString(0, string, sizeof(string));
209 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
210 ed = PROG_TO_EDICT(pr_global_struct->self);
213 PF_ERROR("Program error");
220 Dumps out self, then an error message. The program is aborted and self is
221 removed, but the level can continue.
226 void PF_objerror (void)
229 char string[STRINGTEMP_LENGTH];
231 PF_VarString(0, string, sizeof(string));
232 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
233 ed = PROG_TO_EDICT(pr_global_struct->self);
243 Writes new values for v_forward, v_up, and v_right based on angles
247 void PF_makevectors (void)
249 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
256 Writes new values for v_forward, v_up, and v_right based on the given forward vector
257 vectorvectors(vector, vector)
260 void PF_vectorvectors (void)
262 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
263 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
270 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.
272 setorigin (entity, origin)
275 void PF_setorigin (void)
280 e = G_EDICT(OFS_PARM0);
282 PF_WARNING("setorigin: can not modify world entity\n");
284 PF_WARNING("setorigin: can not modify free entity\n");
285 org = G_VECTOR(OFS_PARM1);
286 VectorCopy (org, e->v->origin);
287 SV_LinkEdict (e, false);
291 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
295 for (i=0 ; i<3 ; i++)
297 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
299 // set derived values
300 VectorCopy (min, e->v->mins);
301 VectorCopy (max, e->v->maxs);
302 VectorSubtract (max, min, e->v->size);
304 SV_LinkEdict (e, false);
311 the size box is rotated by the current angle
312 LordHavoc: no it isn't...
314 setsize (entity, minvector, maxvector)
317 void PF_setsize (void)
322 e = G_EDICT(OFS_PARM0);
324 PF_WARNING("setsize: can not modify world entity\n");
326 PF_WARNING("setsize: can not modify free entity\n");
327 min = G_VECTOR(OFS_PARM1);
328 max = G_VECTOR(OFS_PARM2);
329 SetMinMaxSize (e, min, max, false);
337 setmodel(entity, model)
340 void PF_setmodel (void)
347 e = G_EDICT(OFS_PARM0);
349 PF_WARNING("setmodel: can not modify world entity\n");
351 PF_WARNING("setmodel: can not modify free entity\n");
352 m = G_STRING(OFS_PARM1);
354 // check to see if model was properly precached
355 for (i=0, check = sv.model_precache ; *check ; i++, check++)
356 if (!strcmp(*check, m))
360 PF_WARNING("setmodel: no precache\n");
363 e->v->model = PR_SetString(*check);
364 e->v->modelindex = i;
366 mod = sv.models[ (int)e->v->modelindex];
369 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
371 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
378 broadcast print to everyone on server
383 void PF_bprint (void)
385 char string[STRINGTEMP_LENGTH];
386 PF_VarString(0, string, sizeof(string));
387 SV_BroadcastPrint(string);
394 single print to a specific client
396 sprint(clientent, value)
399 void PF_sprint (void)
403 char string[STRINGTEMP_LENGTH];
405 entnum = G_EDICTNUM(OFS_PARM0);
407 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
409 Con_Print("tried to sprint to a non-client\n");
413 client = svs.clients + entnum-1;
414 if (!client->netconnection)
416 PF_VarString(1, string, sizeof(string));
417 MSG_WriteChar(&client->message,svc_print);
418 MSG_WriteString(&client->message, string);
426 single print to a specific client
428 centerprint(clientent, value)
431 void PF_centerprint (void)
435 char string[STRINGTEMP_LENGTH];
437 entnum = G_EDICTNUM(OFS_PARM0);
439 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
441 Con_Print("tried to sprint to a non-client\n");
445 client = svs.clients + entnum-1;
446 if (!client->netconnection)
448 PF_VarString(1, string, sizeof(string));
449 MSG_WriteChar(&client->message,svc_centerprint);
450 MSG_WriteString(&client->message, string);
458 vector normalize(vector)
461 void PF_normalize (void)
467 value1 = G_VECTOR(OFS_PARM0);
469 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
473 newvalue[0] = newvalue[1] = newvalue[2] = 0;
477 newvalue[0] = value1[0] * new;
478 newvalue[1] = value1[1] * new;
479 newvalue[2] = value1[2] * new;
482 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
497 value1 = G_VECTOR(OFS_PARM0);
499 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
502 G_FLOAT(OFS_RETURN) = new;
509 float vectoyaw(vector)
512 void PF_vectoyaw (void)
517 value1 = G_VECTOR(OFS_PARM0);
519 if (value1[1] == 0 && value1[0] == 0)
523 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
528 G_FLOAT(OFS_RETURN) = yaw;
536 vector vectoangles(vector)
539 void PF_vectoangles (void)
545 value1 = G_VECTOR(OFS_PARM0);
547 if (value1[1] == 0 && value1[0] == 0)
557 // LordHavoc: optimized a bit
560 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
564 else if (value1[1] > 0)
569 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
570 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
575 G_FLOAT(OFS_RETURN+0) = pitch;
576 G_FLOAT(OFS_RETURN+1) = yaw;
577 G_FLOAT(OFS_RETURN+2) = 0;
584 Returns a number from 0<= num < 1
589 void PF_random (void)
593 num = (rand ()&0x7fff) / ((float)0x7fff);
595 G_FLOAT(OFS_RETURN) = num;
602 particle(origin, color, count)
605 void PF_particle (void)
611 org = G_VECTOR(OFS_PARM0);
612 dir = G_VECTOR(OFS_PARM1);
613 color = G_FLOAT(OFS_PARM2);
614 count = G_FLOAT(OFS_PARM3);
615 SV_StartParticle (org, dir, color, count);
625 void PF_ambientsound (void)
630 float vol, attenuation;
631 int i, soundnum, large;
633 pos = G_VECTOR (OFS_PARM0);
634 samp = G_STRING(OFS_PARM1);
635 vol = G_FLOAT(OFS_PARM2);
636 attenuation = G_FLOAT(OFS_PARM3);
638 // check to see if samp was properly precached
639 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
640 if (!strcmp(*check,samp))
645 Con_Printf("no precache: %s\n", samp);
653 // add an svc_spawnambient command to the level signon packet
656 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
658 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
660 for (i=0 ; i<3 ; i++)
661 MSG_WriteDPCoord(&sv.signon, pos[i]);
664 MSG_WriteShort (&sv.signon, soundnum);
666 MSG_WriteByte (&sv.signon, soundnum);
668 MSG_WriteByte (&sv.signon, vol*255);
669 MSG_WriteByte (&sv.signon, attenuation*64);
677 Each entity can have eight independant sound sources, like voice,
680 Channel 0 is an auto-allocate channel, the others override anything
681 already running on that entity/channel pair.
683 An attenuation of 0 will play full volume everywhere in the level.
684 Larger attenuations will drop off.
696 entity = G_EDICT(OFS_PARM0);
697 channel = G_FLOAT(OFS_PARM1);
698 sample = G_STRING(OFS_PARM2);
699 volume = G_FLOAT(OFS_PARM3) * 255;
700 attenuation = G_FLOAT(OFS_PARM4);
702 if (volume < 0 || volume > 255)
703 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
705 if (attenuation < 0 || attenuation > 4)
706 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
708 if (channel < 0 || channel > 7)
709 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
711 SV_StartSound (entity, channel, sample, volume, attenuation);
723 PF_ERROR("break: break statement\n");
730 Used for use tracing and shot targeting
731 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
732 if the tryents flag is set.
734 traceline (vector1, vector2, tryents)
737 void PF_traceline (void)
744 pr_xfunction->builtinsprofile += 30;
746 v1 = G_VECTOR(OFS_PARM0);
747 v2 = G_VECTOR(OFS_PARM1);
748 move = G_FLOAT(OFS_PARM2);
749 ent = G_EDICT(OFS_PARM3);
751 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
753 pr_global_struct->trace_allsolid = trace.allsolid;
754 pr_global_struct->trace_startsolid = trace.startsolid;
755 pr_global_struct->trace_fraction = trace.fraction;
756 pr_global_struct->trace_inwater = trace.inwater;
757 pr_global_struct->trace_inopen = trace.inopen;
758 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
759 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
760 pr_global_struct->trace_plane_dist = trace.plane.dist;
762 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
764 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
765 // FIXME: add trace_endcontents
773 Used for use tracing and shot targeting
774 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
775 if the tryents flag is set.
777 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
780 // LordHavoc: added this for my own use, VERY useful, similar to traceline
781 void PF_tracebox (void)
783 float *v1, *v2, *m1, *m2;
788 pr_xfunction->builtinsprofile += 30;
790 v1 = G_VECTOR(OFS_PARM0);
791 m1 = G_VECTOR(OFS_PARM1);
792 m2 = G_VECTOR(OFS_PARM2);
793 v2 = G_VECTOR(OFS_PARM3);
794 move = G_FLOAT(OFS_PARM4);
795 ent = G_EDICT(OFS_PARM5);
797 trace = SV_Move (v1, m1, m2, v2, move, ent);
799 pr_global_struct->trace_allsolid = trace.allsolid;
800 pr_global_struct->trace_startsolid = trace.startsolid;
801 pr_global_struct->trace_fraction = trace.fraction;
802 pr_global_struct->trace_inwater = trace.inwater;
803 pr_global_struct->trace_inopen = trace.inopen;
804 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
805 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
806 pr_global_struct->trace_plane_dist = trace.plane.dist;
808 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
810 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
813 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
814 void PF_TraceToss (void)
820 pr_xfunction->builtinsprofile += 600;
822 ent = G_EDICT(OFS_PARM0);
823 if (ent == sv.edicts)
824 PF_WARNING("tracetoss: can not use world entity\n");
825 ignore = G_EDICT(OFS_PARM1);
827 trace = SV_Trace_Toss (ent, ignore);
829 pr_global_struct->trace_allsolid = trace.allsolid;
830 pr_global_struct->trace_startsolid = trace.startsolid;
831 pr_global_struct->trace_fraction = trace.fraction;
832 pr_global_struct->trace_inwater = trace.inwater;
833 pr_global_struct->trace_inopen = trace.inopen;
834 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
835 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
836 pr_global_struct->trace_plane_dist = trace.plane.dist;
838 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
840 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
848 Returns true if the given entity can move to the given position from it's
849 current position by walking or rolling.
851 scalar checkpos (entity, vector)
854 void PF_checkpos (void)
858 //============================================================================
861 qbyte checkpvs[MAX_MAP_LEAFS/8];
863 int PF_newcheckclient (int check)
869 // cycle to the next one
871 check = bound(1, check, svs.maxclients);
872 if (check == svs.maxclients)
880 pr_xfunction->builtinsprofile++;
882 if (i == svs.maxclients+1)
884 // look up the client's edict
886 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
887 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
889 // found a valid client (possibly the same one again)
893 // get the PVS for the entity
894 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
896 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
897 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
906 Returns a client (or object that has a client enemy) that would be a
909 If there is more than one valid option, they are cycled each frame
911 If (self.origin + self.viewofs) is not in the PVS of the current target,
912 it is not returned at all.
917 int c_invis, c_notvis;
918 void PF_checkclient (void)
923 // find a new check if on a new frame
924 if (sv.time - sv.lastchecktime >= 0.1)
926 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
927 sv.lastchecktime = sv.time;
930 // return check if it might be visible
931 ent = EDICT_NUM(sv.lastcheck);
932 if (ent->e->free || ent->v->health <= 0)
934 RETURN_EDICT(sv.edicts);
938 // if current entity can't possibly see the check entity, return 0
939 self = PROG_TO_EDICT(pr_global_struct->self);
940 VectorAdd(self->v->origin, self->v->view_ofs, view);
941 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
944 RETURN_EDICT(sv.edicts);
948 // might be able to see it
953 //============================================================================
960 Sends text over to the client's execution buffer
962 stuffcmd (clientent, value)
965 void PF_stuffcmd (void)
971 entnum = G_EDICTNUM(OFS_PARM0);
972 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
974 Con_Print("Can't stuffcmd to a non-client\n");
977 str = G_STRING(OFS_PARM1);
980 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
981 Host_ClientCommands ("%s", str);
989 Sends text to server console
994 void PF_localcmd (void)
996 Cbuf_AddText(G_STRING(OFS_PARM0));
1008 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1018 void PF_cvar_set (void)
1020 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1027 Returns a chain of entities that have origins within a spherical area
1029 findradius (origin, radius)
1032 void PF_findradius (void)
1034 edict_t *ent, *chain;
1041 chain = (edict_t *)sv.edicts;
1043 org = G_VECTOR(OFS_PARM0);
1044 radius = G_FLOAT(OFS_PARM1);
1045 radius2 = radius * radius;
1047 ent = NEXT_EDICT(sv.edicts);
1048 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1050 pr_xfunction->builtinsprofile++;
1053 if (ent->v->solid == SOLID_NOT)
1056 // LordHavoc: compare against bounding box rather than center,
1057 // and use DotProduct instead of Length, major speedup
1058 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1059 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1060 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1061 if (DotProduct(eorg, eorg) > radius2)
1064 ent->v->chain = EDICT_TO_PROG(chain);
1068 RETURN_EDICT(chain);
1077 void PF_dprint (void)
1079 char string[STRINGTEMP_LENGTH];
1080 if (developer.integer)
1082 PF_VarString(0, string, sizeof(string));
1091 v = G_FLOAT(OFS_PARM0);
1093 s = PR_GetTempString();
1094 if ((float)((int)v) == v)
1095 sprintf(s, "%i", (int)v);
1097 sprintf(s, "%f", v);
1098 G_INT(OFS_RETURN) = PR_SetString(s);
1104 v = G_FLOAT(OFS_PARM0);
1105 G_FLOAT(OFS_RETURN) = fabs(v);
1111 s = PR_GetTempString();
1112 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1113 G_INT(OFS_RETURN) = PR_SetString(s);
1119 s = PR_GetTempString();
1120 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1121 G_INT(OFS_RETURN) = PR_SetString(s);
1124 void PF_Spawn (void)
1127 pr_xfunction->builtinsprofile += 20;
1132 void PF_Remove (void)
1135 pr_xfunction->builtinsprofile += 20;
1137 ed = G_EDICT(OFS_PARM0);
1138 if (ed == sv.edicts)
1139 PF_WARNING("remove: tried to remove world\n");
1140 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1141 PF_WARNING("remove: tried to remove a client\n");
1142 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1143 if (ed->e->free && developer.integer)
1144 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1149 // entity (entity start, .string field, string match) find = #5;
1157 e = G_EDICTNUM(OFS_PARM0);
1158 f = G_INT(OFS_PARM1);
1159 s = G_STRING(OFS_PARM2);
1162 RETURN_EDICT(sv.edicts);
1166 for (e++ ; e < sv.num_edicts ; e++)
1168 pr_xfunction->builtinsprofile++;
1182 RETURN_EDICT(sv.edicts);
1185 // LordHavoc: added this for searching float, int, and entity reference fields
1186 void PF_FindFloat (void)
1193 e = G_EDICTNUM(OFS_PARM0);
1194 f = G_INT(OFS_PARM1);
1195 s = G_FLOAT(OFS_PARM2);
1197 for (e++ ; e < sv.num_edicts ; e++)
1199 pr_xfunction->builtinsprofile++;
1203 if (E_FLOAT(ed,f) == s)
1210 RETURN_EDICT(sv.edicts);
1213 // chained search for strings in entity fields
1214 // entity(.string field, string match) findchain = #402;
1215 void PF_findchain (void)
1220 edict_t *ent, *chain;
1222 chain = (edict_t *)sv.edicts;
1224 f = G_INT(OFS_PARM0);
1225 s = G_STRING(OFS_PARM1);
1228 RETURN_EDICT(sv.edicts);
1232 ent = NEXT_EDICT(sv.edicts);
1233 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1235 pr_xfunction->builtinsprofile++;
1238 t = E_STRING(ent,f);
1244 ent->v->chain = EDICT_TO_PROG(chain);
1248 RETURN_EDICT(chain);
1251 // LordHavoc: chained search for float, int, and entity reference fields
1252 // entity(.string field, float match) findchainfloat = #403;
1253 void PF_findchainfloat (void)
1258 edict_t *ent, *chain;
1260 chain = (edict_t *)sv.edicts;
1262 f = G_INT(OFS_PARM0);
1263 s = G_FLOAT(OFS_PARM1);
1265 ent = NEXT_EDICT(sv.edicts);
1266 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1268 pr_xfunction->builtinsprofile++;
1271 if (E_FLOAT(ent,f) != s)
1274 ent->v->chain = EDICT_TO_PROG(chain);
1278 RETURN_EDICT(chain);
1281 void PR_CheckEmptyString (char *s)
1284 PF_ERROR("Bad string");
1287 void PF_precache_file (void)
1288 { // precache_file is only used to copy files with qcc, it does nothing
1289 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1292 void PF_precache_sound (void)
1297 if (sv.state != ss_loading)
1298 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1300 s = G_STRING(OFS_PARM0);
1301 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1302 PR_CheckEmptyString (s);
1304 for (i=0 ; i<MAX_SOUNDS ; i++)
1306 if (!sv.sound_precache[i])
1308 sv.sound_precache[i] = s;
1311 if (!strcmp(sv.sound_precache[i], s))
1314 PF_ERROR("PF_precache_sound: overflow");
1317 void PF_precache_model (void)
1322 if (sv.state != ss_loading)
1323 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1325 s = G_STRING(OFS_PARM0);
1326 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1328 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1329 PR_CheckEmptyString (s);
1331 for (i=0 ; i<MAX_MODELS ; i++)
1333 if (!sv.model_precache[i])
1335 sv.model_precache[i] = s;
1336 sv.models[i] = Mod_ForName (s, true, false, false);
1339 if (!strcmp(sv.model_precache[i], s))
1342 PF_ERROR("PF_precache_model: overflow");
1346 void PF_coredump (void)
1351 void PF_traceon (void)
1356 void PF_traceoff (void)
1361 void PF_eprint (void)
1363 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1370 float(float yaw, float dist) walkmove
1373 void PF_walkmove (void)
1381 // assume failure if it returns early
1382 G_FLOAT(OFS_RETURN) = 0;
1384 ent = PROG_TO_EDICT(pr_global_struct->self);
1385 if (ent == sv.edicts)
1386 PF_WARNING("walkmove: can not modify world entity\n");
1388 PF_WARNING("walkmove: can not modify free entity\n");
1389 yaw = G_FLOAT(OFS_PARM0);
1390 dist = G_FLOAT(OFS_PARM1);
1392 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1395 yaw = yaw*M_PI*2 / 360;
1397 move[0] = cos(yaw)*dist;
1398 move[1] = sin(yaw)*dist;
1401 // save program state, because SV_movestep may call other progs
1402 oldf = pr_xfunction;
1403 oldself = pr_global_struct->self;
1405 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1408 // restore program state
1409 pr_xfunction = oldf;
1410 pr_global_struct->self = oldself;
1420 void PF_droptofloor (void)
1426 // assume failure if it returns early
1427 G_FLOAT(OFS_RETURN) = 0;
1429 ent = PROG_TO_EDICT(pr_global_struct->self);
1430 if (ent == sv.edicts)
1431 PF_WARNING("droptofloor: can not modify world entity\n");
1433 PF_WARNING("droptofloor: can not modify free entity\n");
1435 VectorCopy (ent->v->origin, end);
1438 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1440 if (trace.fraction != 1)
1442 VectorCopy (trace.endpos, ent->v->origin);
1443 SV_LinkEdict (ent, false);
1444 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1445 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1446 G_FLOAT(OFS_RETURN) = 1;
1447 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1448 ent->e->suspendedinairflag = true;
1456 void(float style, string value) lightstyle
1459 void PF_lightstyle (void)
1466 style = G_FLOAT(OFS_PARM0);
1467 val = G_STRING(OFS_PARM1);
1469 // change the string in sv
1470 sv.lightstyles[style] = val;
1472 // send message to all clients on this server
1473 if (sv.state != ss_active)
1476 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1478 if (client->netconnection)
1480 MSG_WriteChar (&client->message, svc_lightstyle);
1481 MSG_WriteChar (&client->message,style);
1482 MSG_WriteString (&client->message, val);
1490 f = G_FLOAT(OFS_PARM0);
1492 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1494 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1496 void PF_floor (void)
1498 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1502 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1511 void PF_checkbottom (void)
1513 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1521 void PF_pointcontents (void)
1523 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1530 entity nextent(entity)
1533 void PF_nextent (void)
1538 i = G_EDICTNUM(OFS_PARM0);
1541 pr_xfunction->builtinsprofile++;
1543 if (i == sv.num_edicts)
1545 RETURN_EDICT(sv.edicts);
1561 Pick a vector for the player to shoot along
1562 vector aim(entity, missilespeed)
1567 edict_t *ent, *check, *bestent;
1568 vec3_t start, dir, end, bestdir;
1571 float dist, bestdist;
1574 // assume failure if it returns early
1575 VectorClear(G_VECTOR(OFS_RETURN));
1577 ent = G_EDICT(OFS_PARM0);
1578 if (ent == sv.edicts)
1579 PF_WARNING("aim: can not use world entity\n");
1581 PF_WARNING("aim: can not use free entity\n");
1582 speed = G_FLOAT(OFS_PARM1);
1584 VectorCopy (ent->v->origin, start);
1587 // try sending a trace straight
1588 VectorCopy (pr_global_struct->v_forward, dir);
1589 VectorMA (start, 2048, dir, end);
1590 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1591 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1592 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1594 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1599 // try all possible entities
1600 VectorCopy (dir, bestdir);
1601 bestdist = sv_aim.value;
1604 check = NEXT_EDICT(sv.edicts);
1605 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1607 pr_xfunction->builtinsprofile++;
1608 if (check->v->takedamage != DAMAGE_AIM)
1612 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1613 continue; // don't aim at teammate
1614 for (j=0 ; j<3 ; j++)
1615 end[j] = check->v->origin[j]
1616 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1617 VectorSubtract (end, start, dir);
1618 VectorNormalize (dir);
1619 dist = DotProduct (dir, pr_global_struct->v_forward);
1620 if (dist < bestdist)
1621 continue; // to far to turn
1622 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1623 if (tr.ent == check)
1624 { // can shoot at this one
1632 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1633 dist = DotProduct (dir, pr_global_struct->v_forward);
1634 VectorScale (pr_global_struct->v_forward, dist, end);
1636 VectorNormalize (end);
1637 VectorCopy (end, G_VECTOR(OFS_RETURN));
1641 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1649 This was a major timewaster in progs, so it was converted to C
1652 void PF_changeyaw (void)
1655 float ideal, current, move, speed;
1657 ent = PROG_TO_EDICT(pr_global_struct->self);
1658 if (ent == sv.edicts)
1659 PF_WARNING("changeyaw: can not modify world entity\n");
1661 PF_WARNING("changeyaw: can not modify free entity\n");
1662 current = ANGLEMOD(ent->v->angles[1]);
1663 ideal = ent->v->ideal_yaw;
1664 speed = ent->v->yaw_speed;
1666 if (current == ideal)
1668 move = ideal - current;
1669 if (ideal > current)
1690 ent->v->angles[1] = ANGLEMOD (current + move);
1698 void PF_changepitch (void)
1701 float ideal, current, move, speed;
1704 ent = G_EDICT(OFS_PARM0);
1705 if (ent == sv.edicts)
1706 PF_WARNING("changepitch: can not modify world entity\n");
1708 PF_WARNING("changepitch: can not modify free entity\n");
1709 current = ANGLEMOD( ent->v->angles[0] );
1710 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1711 ideal = val->_float;
1714 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1717 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1718 speed = val->_float;
1721 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1725 if (current == ideal)
1727 move = ideal - current;
1728 if (ideal > current)
1749 ent->v->angles[0] = ANGLEMOD (current + move);
1753 ===============================================================================
1757 ===============================================================================
1760 #define MSG_BROADCAST 0 // unreliable to all
1761 #define MSG_ONE 1 // reliable to one (msg_entity)
1762 #define MSG_ALL 2 // reliable to all
1763 #define MSG_INIT 3 // write to the init string
1765 sizebuf_t *WriteDest (void)
1771 dest = G_FLOAT(OFS_PARM0);
1775 return &sv.datagram;
1778 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1779 entnum = NUM_FOR_EDICT(ent);
1780 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1781 Host_Error("WriteDest: tried to write to non-client\n");
1782 return &svs.clients[entnum-1].message;
1785 return &sv.reliable_datagram;
1791 Host_Error("WriteDest: bad destination");
1798 void PF_WriteByte (void)
1800 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1803 void PF_WriteChar (void)
1805 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1808 void PF_WriteShort (void)
1810 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1813 void PF_WriteLong (void)
1815 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1818 void PF_WriteAngle (void)
1820 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1823 void PF_WriteCoord (void)
1825 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1828 void PF_WriteString (void)
1830 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1834 void PF_WriteEntity (void)
1836 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1839 //=============================================================================
1841 void PF_makestatic (void)
1846 ent = G_EDICT(OFS_PARM0);
1847 if (ent == sv.edicts)
1848 PF_WARNING("makestatic: can not modify world entity\n");
1850 PF_WARNING("makestatic: can not modify free entity\n");
1853 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1858 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1859 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1860 MSG_WriteShort (&sv.signon, ent->v->frame);
1864 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1865 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1866 MSG_WriteByte (&sv.signon, ent->v->frame);
1869 MSG_WriteByte (&sv.signon, ent->v->colormap);
1870 MSG_WriteByte (&sv.signon, ent->v->skin);
1871 for (i=0 ; i<3 ; i++)
1873 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1874 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1877 // throw the entity away now
1881 //=============================================================================
1888 void PF_setspawnparms (void)
1894 ent = G_EDICT(OFS_PARM0);
1895 i = NUM_FOR_EDICT(ent);
1896 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1898 Con_Print("tried to setspawnparms on a non-client\n");
1902 // copy spawn parms out of the client_t
1903 client = svs.clients + i-1;
1904 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1905 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1913 void PF_changelevel (void)
1917 // make sure we don't issue two changelevels
1918 if (svs.changelevel_issued)
1920 svs.changelevel_issued = true;
1922 s = G_STRING(OFS_PARM0);
1923 Cbuf_AddText (va("changelevel %s\n",s));
1928 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1933 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1938 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1945 Returns a vector of length < 1
1950 void PF_randomvec (void)
1955 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1956 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1957 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1959 while (DotProduct(temp, temp) >= 1);
1960 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1967 Returns a color vector indicating the lighting at the requested point.
1969 (Internal Operation note: actually measures the light beneath the point, just like
1970 the model lighting on the client)
1975 void PF_GetLight (void)
1977 vec3_t ambientcolor, diffusecolor, diffusenormal;
1979 p = G_VECTOR(OFS_PARM0);
1980 VectorClear(ambientcolor);
1981 VectorClear(diffusecolor);
1982 VectorClear(diffusenormal);
1983 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1984 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1985 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
1988 #define MAX_QC_CVARS 128
1989 cvar_t qc_cvar[MAX_QC_CVARS];
1992 void PF_registercvar (void)
1996 name = G_STRING(OFS_PARM0);
1997 value = G_STRING(OFS_PARM1);
1998 G_FLOAT(OFS_RETURN) = 0;
1999 // first check to see if it has already been defined
2000 if (Cvar_FindVar (name))
2003 // check for overlap with a command
2004 if (Cmd_Exists (name))
2006 Con_Printf("PF_registercvar: %s is a command\n", name);
2010 if (currentqc_cvar >= MAX_QC_CVARS)
2011 PF_ERROR("PF_registercvar: ran out of cvar slots\n");
2013 // copy the name and value
2014 variable = &qc_cvar[currentqc_cvar++];
2015 variable->name = Z_Malloc (strlen(name)+1);
2016 strcpy (variable->name, name);
2017 variable->string = Z_Malloc (strlen(value)+1);
2018 strcpy (variable->string, value);
2019 variable->value = atof (value);
2021 Cvar_RegisterVariable(variable);
2022 G_FLOAT(OFS_RETURN) = 1; // success
2029 returns the minimum of two supplied floats
2036 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2038 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2039 else if (pr_argc >= 3)
2042 float f = G_FLOAT(OFS_PARM0);
2043 for (i = 1;i < pr_argc;i++)
2044 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2045 f = G_FLOAT((OFS_PARM0+i*3));
2046 G_FLOAT(OFS_RETURN) = f;
2050 G_FLOAT(OFS_RETURN) = 0;
2051 PF_WARNING("min: must supply at least 2 floats\n");
2059 returns the maximum of two supplied floats
2066 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2068 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2069 else if (pr_argc >= 3)
2072 float f = G_FLOAT(OFS_PARM0);
2073 for (i = 1;i < pr_argc;i++)
2074 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2075 f = G_FLOAT((OFS_PARM0+i*3));
2076 G_FLOAT(OFS_RETURN) = f;
2080 G_FLOAT(OFS_RETURN) = 0;
2081 PF_WARNING("max: must supply at least 2 floats\n");
2089 returns number bounded by supplied range
2091 min(min, value, max)
2094 void PF_bound (void)
2096 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2103 returns a raised to power b
2110 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2117 copies data from one entity to another
2119 copyentity(src, dst)
2122 void PF_copyentity (void)
2125 in = G_EDICT(OFS_PARM0);
2126 if (in == sv.edicts)
2127 PF_WARNING("copyentity: can not read world entity\n");
2129 PF_WARNING("copyentity: can not read free entity\n");
2130 out = G_EDICT(OFS_PARM1);
2131 if (out == sv.edicts)
2132 PF_WARNING("copyentity: can not modify world entity\n");
2134 PF_WARNING("copyentity: can not modify free entity\n");
2135 memcpy(out->v, in->v, progs->entityfields * 4);
2142 sets the color of a client and broadcasts the update to all connected clients
2144 setcolor(clientent, value)
2147 void PF_setcolor (void)
2153 entnum = G_EDICTNUM(OFS_PARM0);
2154 i = G_FLOAT(OFS_PARM1);
2156 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2158 Con_Print("tried to setcolor a non-client\n");
2162 client = svs.clients + entnum-1;
2163 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2166 client->old_colors = i;
2167 client->edict->v->team = (i & 15) + 1;
2169 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2170 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2171 MSG_WriteByte (&sv.reliable_datagram, i);
2178 effect(origin, modelname, startframe, framecount, framerate)
2181 void PF_effect (void)
2184 s = G_STRING(OFS_PARM1);
2186 PF_WARNING("effect: no model specified\n");
2188 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2191 void PF_te_blood (void)
2193 if (G_FLOAT(OFS_PARM2) < 1)
2195 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2196 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2198 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2199 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2200 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2202 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2203 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2204 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2206 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2209 void PF_te_bloodshower (void)
2211 if (G_FLOAT(OFS_PARM3) < 1)
2213 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2214 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2217 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2218 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2220 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2221 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2222 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2224 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2226 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2229 void PF_te_explosionrgb (void)
2231 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2232 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2238 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2239 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2240 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2243 void PF_te_particlecube (void)
2245 if (G_FLOAT(OFS_PARM3) < 1)
2247 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2248 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2250 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2251 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2252 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2254 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2255 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2256 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2258 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2259 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2260 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2262 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2264 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2265 // gravity true/false
2266 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2268 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2271 void PF_te_particlerain (void)
2273 if (G_FLOAT(OFS_PARM3) < 1)
2275 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2276 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2278 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2279 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2280 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2282 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2286 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2287 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2288 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2290 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2292 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2295 void PF_te_particlesnow (void)
2297 if (G_FLOAT(OFS_PARM3) < 1)
2299 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2300 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2302 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2303 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2306 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2307 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2308 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2310 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2311 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2312 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2314 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2316 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2319 void PF_te_spark (void)
2321 if (G_FLOAT(OFS_PARM2) < 1)
2323 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2324 MSG_WriteByte(&sv.datagram, TE_SPARK);
2326 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2327 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2328 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2330 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2331 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2332 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2334 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2337 void PF_te_gunshotquad (void)
2339 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2340 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2342 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2343 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2344 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2347 void PF_te_spikequad (void)
2349 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2350 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2352 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2353 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2354 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2357 void PF_te_superspikequad (void)
2359 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2360 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2362 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2363 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2364 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2367 void PF_te_explosionquad (void)
2369 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2370 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
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]);
2377 void PF_te_smallflash (void)
2379 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2380 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2382 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2383 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2384 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2387 void PF_te_customflash (void)
2389 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2391 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2394 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2395 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2396 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2398 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2400 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2402 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2403 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2404 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2407 void PF_te_gunshot (void)
2409 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2410 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2412 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2413 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2414 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2417 void PF_te_spike (void)
2419 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2420 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2422 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2423 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2424 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2427 void PF_te_superspike (void)
2429 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2430 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2432 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2433 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2434 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2437 void PF_te_explosion (void)
2439 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2440 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2442 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2443 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2447 void PF_te_tarexplosion (void)
2449 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2450 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2452 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2453 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2454 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2457 void PF_te_wizspike (void)
2459 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2462 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2467 void PF_te_knightspike (void)
2469 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2470 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2472 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2473 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2474 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2477 void PF_te_lavasplash (void)
2479 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2480 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2483 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2484 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2487 void PF_te_teleport (void)
2489 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2490 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2494 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2497 void PF_te_explosion2 (void)
2499 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2500 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2502 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2503 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2504 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2506 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2507 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2510 void PF_te_lightning1 (void)
2512 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2513 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2515 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2517 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2518 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2519 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2521 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2522 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2523 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2526 void PF_te_lightning2 (void)
2528 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2529 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2531 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2533 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2534 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2535 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2537 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2538 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2539 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2542 void PF_te_lightning3 (void)
2544 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2545 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2547 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2549 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2550 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2551 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2553 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2554 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2555 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2558 void PF_te_beam (void)
2560 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2561 MSG_WriteByte(&sv.datagram, TE_BEAM);
2563 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2565 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2566 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2567 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2569 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2570 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2571 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2574 void PF_te_plasmaburn (void)
2576 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2577 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2578 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2579 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2580 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2583 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2586 vec3_t v1, clipplanenormal, normal;
2587 vec_t clipplanedist, clipdist;
2589 if (surf->flags & SURF_PLANEBACK)
2590 VectorNegate(surf->plane->normal, normal);
2592 VectorCopy(surf->plane->normal, normal);
2593 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2595 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2596 VectorNormalizeFast(v1);
2597 CrossProduct(v1, normal, clipplanenormal);
2598 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2599 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2602 clipdist = -clipdist;
2603 VectorMA(out, clipdist, clipplanenormal, out);
2608 static msurface_t *getsurface(edict_t *ed, int surfnum)
2612 if (!ed || ed->e->free)
2614 modelindex = ed->v->modelindex;
2615 if (modelindex < 1 || modelindex >= MAX_MODELS)
2617 model = sv.models[modelindex];
2618 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2620 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2624 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2625 void PF_getsurfacenumpoints(void)
2628 // return 0 if no such surface
2629 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2631 G_FLOAT(OFS_RETURN) = 0;
2635 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2637 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2638 void PF_getsurfacepoint(void)
2643 VectorClear(G_VECTOR(OFS_RETURN));
2644 ed = G_EDICT(OFS_PARM0);
2645 if (!ed || ed->e->free)
2647 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2649 pointnum = G_FLOAT(OFS_PARM2);
2650 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2652 // FIXME: implement rotation/scaling
2653 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2655 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2656 void PF_getsurfacenormal(void)
2659 VectorClear(G_VECTOR(OFS_RETURN));
2660 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2662 // FIXME: implement rotation/scaling
2663 if (surf->flags & SURF_PLANEBACK)
2664 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2666 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2668 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2669 void PF_getsurfacetexture(void)
2672 G_INT(OFS_RETURN) = 0;
2673 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2675 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2677 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2678 void PF_getsurfacenearpoint(void)
2680 int surfnum, best, modelindex;
2682 vec_t dist, bestdist;
2687 G_FLOAT(OFS_RETURN) = -1;
2688 ed = G_EDICT(OFS_PARM0);
2689 point = G_VECTOR(OFS_PARM1);
2691 if (!ed || ed->e->free)
2693 modelindex = ed->v->modelindex;
2694 if (modelindex < 1 || modelindex >= MAX_MODELS)
2696 model = sv.models[modelindex];
2697 if (!model->brushq1.numsurfaces)
2700 // FIXME: implement rotation/scaling
2701 VectorSubtract(point, ed->v->origin, p);
2703 bestdist = 1000000000;
2704 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2706 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2707 dist = PlaneDiff(p, surf->plane);
2709 if (dist < bestdist)
2711 clippointtosurface(surf, p, clipped);
2712 VectorSubtract(clipped, p, clipped);
2713 dist += DotProduct(clipped, clipped);
2714 if (dist < bestdist)
2721 G_FLOAT(OFS_RETURN) = best;
2723 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2724 void PF_getsurfaceclippedpoint(void)
2729 VectorClear(G_VECTOR(OFS_RETURN));
2730 ed = G_EDICT(OFS_PARM0);
2731 if (!ed || ed->e->free)
2733 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2735 // FIXME: implement rotation/scaling
2736 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2737 clippointtosurface(surf, p, out);
2738 // FIXME: implement rotation/scaling
2739 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2742 #define MAX_PRFILES 256
2744 qfile_t *pr_files[MAX_PRFILES];
2746 void PR_Files_Init(void)
2748 memset(pr_files, 0, sizeof(pr_files));
2751 void PR_Files_CloseAll(void)
2754 for (i = 0;i < MAX_PRFILES;i++)
2757 FS_Close(pr_files[i]);
2762 //float(string s) stof = #81; // get numerical value from a string
2765 char string[STRINGTEMP_LENGTH];
2766 PF_VarString(0, string, sizeof(string));
2767 G_FLOAT(OFS_RETURN) = atof(string);
2770 //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
2773 int filenum, mode, i;
2774 char *modestring, *filename;
2775 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2776 if (pr_files[filenum] == NULL)
2778 if (filenum >= MAX_PRFILES)
2780 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2781 G_FLOAT(OFS_RETURN) = -2;
2784 mode = G_FLOAT(OFS_PARM1);
2787 case 0: // FILE_READ
2790 case 1: // FILE_APPEND
2793 case 2: // FILE_WRITE
2797 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2798 G_FLOAT(OFS_RETURN) = -3;
2801 filename = G_STRING(OFS_PARM0);
2802 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2803 // ../ is parent directory on many platforms
2804 // // is parent directory on Amiga
2805 // / at the beginning of a path is root on unix, and parent directory on Amiga
2806 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2807 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2808 for (i = 0;filename[i];i++)
2810 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2812 Con_Printf("PF_fopen: dangerous/confusing/annoying/non-portable filename \"%s\" not allowed. (contains control characters or // or .. or : or \\ or begins with /)\n", filename);
2813 G_FLOAT(OFS_RETURN) = -4;
2817 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2819 if (pr_files[filenum] == NULL && modestring == "rb")
2820 pr_files[filenum] = FS_Open(filename, modestring, false);
2822 if (pr_files[filenum] == NULL)
2823 G_FLOAT(OFS_RETURN) = -1;
2825 G_FLOAT(OFS_RETURN) = filenum;
2828 //void(float fhandle) fclose = #111; // closes a file
2829 void PF_fclose(void)
2831 int filenum = G_FLOAT(OFS_PARM0);
2832 if (filenum < 0 || filenum >= MAX_PRFILES)
2834 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2837 if (pr_files[filenum] == NULL)
2839 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2842 FS_Close(pr_files[filenum]);
2843 pr_files[filenum] = NULL;
2846 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2850 static char string[STRINGTEMP_LENGTH];
2851 int filenum = G_FLOAT(OFS_PARM0);
2852 if (filenum < 0 || filenum >= MAX_PRFILES)
2854 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2857 if (pr_files[filenum] == NULL)
2859 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2865 c = FS_Getc(pr_files[filenum]);
2866 if (c == '\r' || c == '\n' || c < 0)
2868 if (end < STRINGTEMP_LENGTH - 1)
2872 // remove \n following \r
2874 c = FS_Getc(pr_files[filenum]);
2875 if (developer.integer)
2876 Con_Printf("fgets: %s\n", string);
2878 G_INT(OFS_RETURN) = PR_SetString(string);
2880 G_INT(OFS_RETURN) = 0;
2883 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2887 char string[STRINGTEMP_LENGTH];
2888 int filenum = G_FLOAT(OFS_PARM0);
2889 if (filenum < 0 || filenum >= MAX_PRFILES)
2891 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2894 if (pr_files[filenum] == NULL)
2896 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2899 PF_VarString(1, string, sizeof(string));
2900 if ((stringlength = strlen(string)))
2901 FS_Write(pr_files[filenum], string, stringlength);
2902 if (developer.integer)
2903 Con_Printf("fputs: %s\n", string);
2906 //float(string s) strlen = #114; // returns how many characters are in a string
2907 void PF_strlen(void)
2910 s = G_STRING(OFS_PARM0);
2912 G_FLOAT(OFS_RETURN) = strlen(s);
2914 G_FLOAT(OFS_RETURN) = 0;
2917 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2918 void PF_strcat(void)
2920 char *s = PR_GetTempString();
2921 PF_VarString(0, s, STRINGTEMP_LENGTH);
2922 G_INT(OFS_RETURN) = PR_SetString(s);
2925 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2926 void PF_substring(void)
2928 int i, start, length;
2929 char *s, *string = PR_GetTempString();
2930 s = G_STRING(OFS_PARM0);
2931 start = G_FLOAT(OFS_PARM1);
2932 length = G_FLOAT(OFS_PARM2);
2935 for (i = 0;i < start && *s;i++, s++);
2936 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2939 G_INT(OFS_RETURN) = PR_SetString(string);
2942 //vector(string s) stov = #117; // returns vector value from a string
2945 char string[STRINGTEMP_LENGTH];
2946 PF_VarString(0, string, sizeof(string));
2947 Math_atov(string, G_VECTOR(OFS_RETURN));
2950 //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)
2951 void PF_strzone(void)
2954 in = G_STRING(OFS_PARM0);
2955 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2957 G_INT(OFS_RETURN) = PR_SetString(out);
2960 //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!!!)
2961 void PF_strunzone(void)
2963 Mem_Free(G_STRING(OFS_PARM0));
2966 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2967 //this function originally written by KrimZon, made shorter by LordHavoc
2968 void PF_clientcommand (void)
2970 client_t *temp_client;
2973 //find client for this entity
2974 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2975 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2977 Con_Print("PF_clientcommand: entity is not a client\n");
2981 temp_client = host_client;
2982 host_client = svs.clients + i;
2983 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2984 host_client = temp_client;
2987 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2988 //this function originally written by KrimZon, made shorter by LordHavoc
2989 //20040203: rewritten by LordHavoc (no longer uses allocations)
2991 char *tokens[256], tokenbuf[4096];
2992 void PF_tokenize (void)
2996 p = G_STRING(OFS_PARM0);
3000 while(COM_ParseToken(&p, false))
3002 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3004 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3006 tokens[num_tokens++] = tokenbuf + pos;
3007 strcpy(tokenbuf + pos, com_token);
3008 pos += strlen(com_token) + 1;
3011 G_FLOAT(OFS_RETURN) = num_tokens;
3014 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3015 //this function originally written by KrimZon, made shorter by LordHavoc
3018 int token_num = G_FLOAT(OFS_PARM0);
3019 if (token_num >= 0 && token_num < num_tokens)
3020 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3022 G_INT(OFS_RETURN) = PR_SetString("");
3025 //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)
3026 void PF_setattachment (void)
3028 edict_t *e = G_EDICT(OFS_PARM0);
3029 edict_t *tagentity = G_EDICT(OFS_PARM1);
3030 char *tagname = G_STRING(OFS_PARM2);
3036 PF_WARNING("setattachment: can not modify world entity\n");
3038 PF_WARNING("setattachment: can not modify free entity\n");
3040 if (tagentity == NULL)
3041 tagentity = sv.edicts;
3043 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3045 v->edict = EDICT_TO_PROG(tagentity);
3047 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3050 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3052 modelindex = (int)tagentity->v->modelindex;
3053 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3055 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3056 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3057 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3059 if (v->_float == 0 && model->alias.aliasnum_tags)
3060 for (i = 0;i < model->alias.aliasnum_tags;i++)
3061 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3064 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);
3067 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));
3072 /////////////////////////////////////////
3073 // DP_QC_FS_SEARCH extension
3075 // qc fs search handling
3076 #define MAX_SEARCHES 128
3078 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3080 void PR_Search_Init(void)
3082 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3085 void PR_Search_Reset(void)
3088 // reset the fssearch list
3089 for(i = 0; i < MAX_SEARCHES; i++)
3090 if(pr_fssearchlist[i])
3091 FS_FreeSearch(pr_fssearchlist[i]);
3092 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3099 float search_begin(string pattern, float caseinsensitive, float quiet)
3102 void PF_search_begin(void)
3106 int caseinsens, quiet;
3108 pattern = G_STRING(OFS_PARM0);
3110 PR_CheckEmptyString(pattern);
3112 caseinsens = G_FLOAT(OFS_PARM1);
3113 quiet = G_FLOAT(OFS_PARM2);
3115 for(handle = 0; handle < MAX_SEARCHES; handle++)
3116 if(!pr_fssearchlist[handle])
3119 if(handle >= MAX_SEARCHES)
3121 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3122 G_FLOAT(OFS_RETURN) = -2;
3126 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3127 G_FLOAT(OFS_RETURN) = -1;
3129 G_FLOAT(OFS_RETURN) = handle;
3136 void search_end(float handle)
3139 void PF_search_end(void)
3143 handle = G_FLOAT(OFS_PARM0);
3145 if(handle < 0 || handle >= MAX_SEARCHES)
3147 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3150 if(pr_fssearchlist[handle] == NULL)
3152 Con_Printf("PF_search_end: no such handle %i\n", handle);
3156 FS_FreeSearch(pr_fssearchlist[handle]);
3157 pr_fssearchlist[handle] = NULL;
3164 float search_getsize(float handle)
3167 void PF_search_getsize(void)
3171 handle = G_FLOAT(OFS_PARM0);
3173 if(handle < 0 || handle >= MAX_SEARCHES)
3175 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3178 if(pr_fssearchlist[handle] == NULL)
3180 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3184 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3189 VM_search_getfilename
3191 string search_getfilename(float handle, float num)
3194 void PF_search_getfilename(void)
3196 int handle, filenum;
3199 handle = G_FLOAT(OFS_PARM0);
3200 filenum = G_FLOAT(OFS_PARM1);
3202 if(handle < 0 || handle >= MAX_SEARCHES)
3204 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3207 if(pr_fssearchlist[handle] == NULL)
3209 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3212 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3214 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3218 tmp = PR_GetTempString();
3219 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3221 G_INT(OFS_RETURN) = PR_SetString(tmp);
3224 void PF_cvar_string (void)
3230 str = G_STRING(OFS_PARM0);
3231 var = Cvar_FindVar (str);
3233 tmp = PR_GetTempString();
3234 strcpy(tmp, var->string);
3236 G_INT(OFS_RETURN) = PR_SetString(tmp);
3241 builtin_t pr_builtin[] =
3244 PF_makevectors, // #1 void(entity e) makevectors
3245 PF_setorigin, // #2 void(entity e, vector o) setorigin
3246 PF_setmodel, // #3 void(entity e, string m) setmodel
3247 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3248 NULL, // #5 void(entity e, vector min, vector max) setabssize
3249 PF_break, // #6 void() break
3250 PF_random, // #7 float() random
3251 PF_sound, // #8 void(entity e, float chan, string samp) sound
3252 PF_normalize, // #9 vector(vector v) normalize
3253 PF_error, // #10 void(string e) error
3254 PF_objerror, // #11 void(string e) objerror
3255 PF_vlen, // #12 float(vector v) vlen
3256 PF_vectoyaw, // #13 float(vector v) vectoyaw
3257 PF_Spawn, // #14 entity() spawn
3258 PF_Remove, // #15 void(entity e) remove
3259 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3260 PF_checkclient, // #17 entity() clientlist
3261 PF_Find, // #18 entity(entity start, .string fld, string match) find
3262 PF_precache_sound, // #19 void(string s) precache_sound
3263 PF_precache_model, // #20 void(string s) precache_model
3264 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3265 PF_findradius, // #22 entity(vector org, float rad) findradius
3266 PF_bprint, // #23 void(string s) bprint
3267 PF_sprint, // #24 void(entity client, string s) sprint
3268 PF_dprint, // #25 void(string s) dprint
3269 PF_ftos, // #26 void(string s) ftos
3270 PF_vtos, // #27 void(string s) vtos
3271 PF_coredump, // #28 void() coredump
3272 PF_traceon, // #29 void() traceon
3273 PF_traceoff, // #30 void() traceoff
3274 PF_eprint, // #31 void(entity e) eprint
3275 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3277 PF_droptofloor, // #34 float() droptofloor
3278 PF_lightstyle, // #35 void(float style, string value) lightstyle
3279 PF_rint, // #36 float(float v) rint
3280 PF_floor, // #37 float(float v) floor
3281 PF_ceil, // #38 float(float v) ceil
3283 PF_checkbottom, // #40 float(entity e) checkbottom
3284 PF_pointcontents , // #41 float(vector v) pointcontents
3286 PF_fabs, // #43 float(float f) fabs
3287 PF_aim, // #44 vector(entity e, float speed) aim
3288 PF_cvar, // #45 float(string s) cvar
3289 PF_localcmd, // #46 void(string s) localcmd
3290 PF_nextent, // #47 entity(entity e) nextent
3291 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3292 PF_changeyaw, // #49 void() ChangeYaw
3294 PF_vectoangles, // #51 vector(vector v) vectoangles
3295 PF_WriteByte, // #52 void(float to, float f) WriteByte
3296 PF_WriteChar, // #53 void(float to, float f) WriteChar
3297 PF_WriteShort, // #54 void(float to, float f) WriteShort
3298 PF_WriteLong, // #55 void(float to, float f) WriteLong
3299 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3300 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3301 PF_WriteString, // #58 void(float to, string s) WriteString
3302 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3303 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3304 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3305 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3306 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3307 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3308 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3310 SV_MoveToGoal, // #67 void(float step) movetogoal
3311 PF_precache_file, // #68 string(string s) precache_file
3312 PF_makestatic, // #69 void(entity e) makestatic
3313 PF_changelevel, // #70 void(string s) changelevel
3315 PF_cvar_set, // #72 void(string var, string val) cvar_set
3316 PF_centerprint, // #73 void(entity client, strings) centerprint
3317 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3318 PF_precache_model, // #75 string(string s) precache_model2
3319 PF_precache_sound, // #76 string(string s) precache_sound2
3320 PF_precache_file, // #77 string(string s) precache_file2
3321 PF_setspawnparms, // #78 void(entity e) setspawnparms
3324 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3333 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3334 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3335 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3336 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3337 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3338 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3339 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3340 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3341 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3342 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3353 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3354 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3355 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3356 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3357 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3358 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3359 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3360 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3361 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3362 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3363 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3364 a a a a a a a a // #120-199
3365 a a a a a a a a a a // #200-299
3366 a a a a a a a a a a // #300-399
3367 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3368 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3369 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3370 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3371 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3372 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3373 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3374 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3375 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3376 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3377 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3378 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3379 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3380 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3381 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3382 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3383 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3384 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3385 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3386 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3387 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3388 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3389 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3390 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3391 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3392 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3393 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3394 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3395 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3396 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3397 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3398 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3399 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3400 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3401 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3402 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3403 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3404 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3405 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3406 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3407 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3408 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3409 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3410 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3411 PF_search_begin, // #444
3412 PF_search_end, // #445
3413 PF_search_getsize, // #446
3414 PF_search_getfilename, // #447
3415 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3417 a a a a a // #450-499 (LordHavoc)
3420 builtin_t *pr_builtins = pr_builtin;
3421 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3423 void PR_Cmd_Init(void)
3425 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3430 void PR_Cmd_Reset(void)
3432 Mem_EmptyPool(pr_strings_mempool);
3434 PR_Files_CloseAll();