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 =
84 "DP_ENT_CUSTOMCOLORMAP "
85 "DP_ENT_EXTERIORMODELTOCLIENT "
87 "DP_ENT_LOWPRECISION "
90 "DP_GFX_EXTERNALTEXTURES "
92 "DP_GFX_QUAKE3MODELTAGS "
96 "DP_HALFLIFE_MAP_CVAR "
101 "DP_MOVETYPEBOUNCEMISSILE "
108 "DP_QC_FINDCHAINFLAGS "
109 "DP_QC_FINDCHAINFLOAT "
112 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
117 "DP_QC_MULTIPLETEMPSTRINGS "
119 "DP_QC_SINCOSSQRTPOW "
122 "DP_QC_TRACE_MOVETYPE_HITMODEL "
123 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
124 "DP_QC_VECTORVECTORS "
128 "DP_SND_DIRECTIONLESSATTNNONE "
133 "DP_SV_DRAWONLYTOCLIENT "
136 "DP_SV_EXTERIORMODELTOCLIENT "
137 "DP_SV_NODRAWTOCLIENT "
138 "DP_SV_PLAYERPHYSICS "
139 "DP_SV_ROTATINGBMODEL "
145 "DP_TE_EXPLOSIONRGB "
147 "DP_TE_PARTICLECUBE "
148 "DP_TE_PARTICLERAIN "
149 "DP_TE_PARTICLESNOW "
151 "DP_TE_QUADEFFECTS1 "
154 "DP_TE_STANDARDEFFECTBUILTINS "
157 "KRIMZON_SV_PARSECLIENTCOMMAND "
161 "TENEBRAE_GFX_DLIGHTS "
165 qboolean checkextension(char *name)
170 for (e = ENGINE_EXTENSIONS;*e;e++)
177 while (*e && *e != ' ')
179 if (e - start == len)
180 if (!strncasecmp(start, name, len))
190 returns true if the extension is supported by the server
192 checkextension(extensionname)
195 void PF_checkextension (void)
197 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
204 This is a TERMINAL error, which will kill off the entire server.
213 char string[STRINGTEMP_LENGTH];
215 PF_VarString(0, string, sizeof(string));
216 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
217 ed = PROG_TO_EDICT(pr_global_struct->self);
220 PF_ERROR("Program error");
227 Dumps out self, then an error message. The program is aborted and self is
228 removed, but the level can continue.
233 void PF_objerror (void)
236 char string[STRINGTEMP_LENGTH];
238 PF_VarString(0, string, sizeof(string));
239 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
240 ed = PROG_TO_EDICT(pr_global_struct->self);
250 Writes new values for v_forward, v_up, and v_right based on angles
254 void PF_makevectors (void)
256 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
263 Writes new values for v_forward, v_up, and v_right based on the given forward vector
264 vectorvectors(vector, vector)
267 void PF_vectorvectors (void)
269 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
270 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
277 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.
279 setorigin (entity, origin)
282 void PF_setorigin (void)
287 e = G_EDICT(OFS_PARM0);
289 PF_WARNING("setorigin: can not modify world entity\n");
291 PF_WARNING("setorigin: can not modify free entity\n");
292 org = G_VECTOR(OFS_PARM1);
293 VectorCopy (org, e->v->origin);
294 SV_LinkEdict (e, false);
298 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
302 for (i=0 ; i<3 ; i++)
304 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
306 // set derived values
307 VectorCopy (min, e->v->mins);
308 VectorCopy (max, e->v->maxs);
309 VectorSubtract (max, min, e->v->size);
311 SV_LinkEdict (e, false);
318 the size box is rotated by the current angle
319 LordHavoc: no it isn't...
321 setsize (entity, minvector, maxvector)
324 void PF_setsize (void)
329 e = G_EDICT(OFS_PARM0);
331 PF_WARNING("setsize: can not modify world entity\n");
333 PF_WARNING("setsize: can not modify free entity\n");
334 min = G_VECTOR(OFS_PARM1);
335 max = G_VECTOR(OFS_PARM2);
336 SetMinMaxSize (e, min, max, false);
344 setmodel(entity, model)
347 void PF_setmodel (void)
354 e = G_EDICT(OFS_PARM0);
356 PF_WARNING("setmodel: can not modify world entity\n");
358 PF_WARNING("setmodel: can not modify free entity\n");
359 m = G_STRING(OFS_PARM1);
361 // check to see if model was properly precached
362 for (i=0, check = sv.model_precache ; *check ; i++, check++)
363 if (!strcmp(*check, m))
367 PF_WARNING(va("setmodel: no precache for model \"%s\"\n", m));
370 e->v->model = PR_SetString(*check);
371 e->v->modelindex = i;
373 mod = sv.models[ (int)e->v->modelindex];
376 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
378 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
385 broadcast print to everyone on server
390 void PF_bprint (void)
392 char string[STRINGTEMP_LENGTH];
393 PF_VarString(0, string, sizeof(string));
394 SV_BroadcastPrint(string);
401 single print to a specific client
403 sprint(clientent, value)
406 void PF_sprint (void)
410 char string[STRINGTEMP_LENGTH];
412 entnum = G_EDICTNUM(OFS_PARM0);
414 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
416 Con_Print("tried to sprint to a non-client\n");
420 client = svs.clients + entnum-1;
421 if (!client->netconnection)
423 PF_VarString(1, string, sizeof(string));
424 MSG_WriteChar(&client->message,svc_print);
425 MSG_WriteString(&client->message, string);
433 single print to a specific client
435 centerprint(clientent, value)
438 void PF_centerprint (void)
442 char string[STRINGTEMP_LENGTH];
444 entnum = G_EDICTNUM(OFS_PARM0);
446 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
448 Con_Print("tried to sprint to a non-client\n");
452 client = svs.clients + entnum-1;
453 if (!client->netconnection)
455 PF_VarString(1, string, sizeof(string));
456 MSG_WriteChar(&client->message,svc_centerprint);
457 MSG_WriteString(&client->message, string);
465 vector normalize(vector)
468 void PF_normalize (void)
474 value1 = G_VECTOR(OFS_PARM0);
476 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
480 newvalue[0] = newvalue[1] = newvalue[2] = 0;
484 newvalue[0] = value1[0] * new;
485 newvalue[1] = value1[1] * new;
486 newvalue[2] = value1[2] * new;
489 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
504 value1 = G_VECTOR(OFS_PARM0);
506 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
509 G_FLOAT(OFS_RETURN) = new;
516 float vectoyaw(vector)
519 void PF_vectoyaw (void)
524 value1 = G_VECTOR(OFS_PARM0);
526 if (value1[1] == 0 && value1[0] == 0)
530 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
535 G_FLOAT(OFS_RETURN) = yaw;
543 vector vectoangles(vector)
546 void PF_vectoangles (void)
548 double value1[3], forward, yaw, pitch;
550 VectorCopy(G_VECTOR(OFS_PARM0), value1);
552 if (value1[1] == 0 && value1[0] == 0)
562 // LordHavoc: optimized a bit
565 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
569 else if (value1[1] > 0)
574 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
575 pitch = (atan2(value1[2], forward) * 180 / M_PI);
580 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
587 Returns a number from 0<= num < 1
592 void PF_random (void)
596 num = (rand ()&0x7fff) / ((float)0x7fff);
598 G_FLOAT(OFS_RETURN) = num;
605 particle(origin, color, count)
608 void PF_particle (void)
614 org = G_VECTOR(OFS_PARM0);
615 dir = G_VECTOR(OFS_PARM1);
616 color = G_FLOAT(OFS_PARM2);
617 count = G_FLOAT(OFS_PARM3);
618 SV_StartParticle (org, dir, color, count);
628 void PF_ambientsound (void)
633 float vol, attenuation;
636 pos = G_VECTOR (OFS_PARM0);
637 samp = G_STRING(OFS_PARM1);
638 vol = G_FLOAT(OFS_PARM2);
639 attenuation = G_FLOAT(OFS_PARM3);
641 // check to see if samp was properly precached
642 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
643 if (!strcmp(*check,samp))
648 Con_Printf("no precache: %s\n", samp);
656 // add an svc_spawnambient command to the level signon packet
659 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
661 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
663 MSG_WriteVector(&sv.signon, pos, sv.protocol);
666 MSG_WriteShort (&sv.signon, soundnum);
668 MSG_WriteByte (&sv.signon, soundnum);
670 MSG_WriteByte (&sv.signon, vol*255);
671 MSG_WriteByte (&sv.signon, attenuation*64);
679 Each entity can have eight independant sound sources, like voice,
682 Channel 0 is an auto-allocate channel, the others override anything
683 already running on that entity/channel pair.
685 An attenuation of 0 will play full volume everywhere in the level.
686 Larger attenuations will drop off.
698 entity = G_EDICT(OFS_PARM0);
699 channel = G_FLOAT(OFS_PARM1);
700 sample = G_STRING(OFS_PARM2);
701 volume = G_FLOAT(OFS_PARM3) * 255;
702 attenuation = G_FLOAT(OFS_PARM4);
704 if (volume < 0 || volume > 255)
705 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
707 if (attenuation < 0 || attenuation > 4)
708 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
710 if (channel < 0 || channel > 7)
711 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
713 SV_StartSound (entity, channel, sample, volume, attenuation);
725 PF_ERROR("break: break statement\n");
732 Used for use tracing and shot targeting
733 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
734 if the tryents flag is set.
736 traceline (vector1, vector2, tryents)
739 void PF_traceline (void)
746 pr_xfunction->builtinsprofile += 30;
748 v1 = G_VECTOR(OFS_PARM0);
749 v2 = G_VECTOR(OFS_PARM1);
750 move = G_FLOAT(OFS_PARM2);
751 ent = G_EDICT(OFS_PARM3);
753 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
755 pr_global_struct->trace_allsolid = trace.allsolid;
756 pr_global_struct->trace_startsolid = trace.startsolid;
757 pr_global_struct->trace_fraction = trace.fraction;
758 pr_global_struct->trace_inwater = trace.inwater;
759 pr_global_struct->trace_inopen = trace.inopen;
760 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
761 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
762 pr_global_struct->trace_plane_dist = trace.plane.dist;
764 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
766 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
767 // FIXME: add trace_endcontents
775 Used for use tracing and shot targeting
776 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
777 if the tryents flag is set.
779 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
782 // LordHavoc: added this for my own use, VERY useful, similar to traceline
783 void PF_tracebox (void)
785 float *v1, *v2, *m1, *m2;
790 pr_xfunction->builtinsprofile += 30;
792 v1 = G_VECTOR(OFS_PARM0);
793 m1 = G_VECTOR(OFS_PARM1);
794 m2 = G_VECTOR(OFS_PARM2);
795 v2 = G_VECTOR(OFS_PARM3);
796 move = G_FLOAT(OFS_PARM4);
797 ent = G_EDICT(OFS_PARM5);
799 trace = SV_Move (v1, m1, m2, v2, move, ent);
801 pr_global_struct->trace_allsolid = trace.allsolid;
802 pr_global_struct->trace_startsolid = trace.startsolid;
803 pr_global_struct->trace_fraction = trace.fraction;
804 pr_global_struct->trace_inwater = trace.inwater;
805 pr_global_struct->trace_inopen = trace.inopen;
806 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
807 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
808 pr_global_struct->trace_plane_dist = trace.plane.dist;
810 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
812 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
815 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
816 void PF_TraceToss (void)
822 pr_xfunction->builtinsprofile += 600;
824 ent = G_EDICT(OFS_PARM0);
825 if (ent == sv.edicts)
826 PF_WARNING("tracetoss: can not use world entity\n");
827 ignore = G_EDICT(OFS_PARM1);
829 trace = SV_Trace_Toss (ent, ignore);
831 pr_global_struct->trace_allsolid = trace.allsolid;
832 pr_global_struct->trace_startsolid = trace.startsolid;
833 pr_global_struct->trace_fraction = trace.fraction;
834 pr_global_struct->trace_inwater = trace.inwater;
835 pr_global_struct->trace_inopen = trace.inopen;
836 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
837 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
838 pr_global_struct->trace_plane_dist = trace.plane.dist;
840 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
842 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
850 Returns true if the given entity can move to the given position from it's
851 current position by walking or rolling.
853 scalar checkpos (entity, vector)
856 void PF_checkpos (void)
860 //============================================================================
863 qbyte checkpvs[MAX_MAP_LEAFS/8];
865 int PF_newcheckclient (int check)
871 // cycle to the next one
873 check = bound(1, check, svs.maxclients);
874 if (check == svs.maxclients)
882 pr_xfunction->builtinsprofile++;
884 if (i == svs.maxclients+1)
886 // look up the client's edict
888 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
889 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
891 // found a valid client (possibly the same one again)
895 // get the PVS for the entity
896 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
898 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
899 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
908 Returns a client (or object that has a client enemy) that would be a
911 If there is more than one valid option, they are cycled each frame
913 If (self.origin + self.viewofs) is not in the PVS of the current target,
914 it is not returned at all.
919 int c_invis, c_notvis;
920 void PF_checkclient (void)
925 // find a new check if on a new frame
926 if (sv.time - sv.lastchecktime >= 0.1)
928 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
929 sv.lastchecktime = sv.time;
932 // return check if it might be visible
933 ent = EDICT_NUM(sv.lastcheck);
934 if (ent->e->free || ent->v->health <= 0)
936 RETURN_EDICT(sv.edicts);
940 // if current entity can't possibly see the check entity, return 0
941 self = PROG_TO_EDICT(pr_global_struct->self);
942 VectorAdd(self->v->origin, self->v->view_ofs, view);
943 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
946 RETURN_EDICT(sv.edicts);
950 // might be able to see it
955 //============================================================================
962 Sends text over to the client's execution buffer
964 stuffcmd (clientent, value)
967 void PF_stuffcmd (void)
973 entnum = G_EDICTNUM(OFS_PARM0);
974 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
976 Con_Print("Can't stuffcmd to a non-client\n");
979 str = G_STRING(OFS_PARM1);
982 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
983 Host_ClientCommands ("%s", str);
991 Sends text to server console
996 void PF_localcmd (void)
998 Cbuf_AddText(G_STRING(OFS_PARM0));
1010 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1020 void PF_cvar_set (void)
1022 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1029 Returns a chain of entities that have origins within a spherical area
1031 findradius (origin, radius)
1034 void PF_findradius (void)
1036 edict_t *ent, *chain;
1037 vec_t radius, radius2;
1038 vec3_t org, eorg, mins, maxs;
1041 edict_t *touchedicts[MAX_EDICTS];
1043 chain = (edict_t *)sv.edicts;
1045 VectorCopy(G_VECTOR(OFS_PARM0), org);
1046 radius = G_FLOAT(OFS_PARM1);
1047 radius2 = radius * radius;
1049 mins[0] = org[0] - radius;
1050 mins[1] = org[1] - radius;
1051 mins[2] = org[2] - radius;
1052 maxs[0] = org[0] + radius;
1053 maxs[1] = org[1] + radius;
1054 maxs[2] = org[2] + radius;
1055 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1056 if (numtouchedicts > MAX_EDICTS)
1058 // this never happens
1059 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1060 numtouchedicts = MAX_EDICTS;
1062 for (i = 0;i < numtouchedicts;i++)
1064 ent = touchedicts[i];
1065 pr_xfunction->builtinsprofile++;
1066 // LordHavoc: compare against bounding box rather than center so it
1067 // doesn't miss large objects, and use DotProduct instead of Length
1068 // for a major speedup
1069 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1070 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1071 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1072 if (DotProduct(eorg, eorg) < radius2)
1074 ent->v->chain = EDICT_TO_PROG(chain);
1079 RETURN_EDICT(chain);
1088 void PF_dprint (void)
1090 char string[STRINGTEMP_LENGTH];
1091 if (developer.integer)
1093 PF_VarString(0, string, sizeof(string));
1102 v = G_FLOAT(OFS_PARM0);
1104 s = PR_GetTempString();
1105 if ((float)((int)v) == v)
1106 sprintf(s, "%i", (int)v);
1108 sprintf(s, "%f", v);
1109 G_INT(OFS_RETURN) = PR_SetString(s);
1115 v = G_FLOAT(OFS_PARM0);
1116 G_FLOAT(OFS_RETURN) = fabs(v);
1122 s = PR_GetTempString();
1123 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1124 G_INT(OFS_RETURN) = PR_SetString(s);
1130 s = PR_GetTempString();
1131 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1132 G_INT(OFS_RETURN) = PR_SetString(s);
1135 void PF_Spawn (void)
1138 pr_xfunction->builtinsprofile += 20;
1143 void PF_Remove (void)
1146 pr_xfunction->builtinsprofile += 20;
1148 ed = G_EDICT(OFS_PARM0);
1149 if (ed == sv.edicts)
1150 PF_WARNING("remove: tried to remove world\n");
1151 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1152 PF_WARNING("remove: tried to remove a client\n");
1153 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1154 if (ed->e->free && developer.integer)
1155 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1160 // entity (entity start, .string field, string match) find = #5;
1168 e = G_EDICTNUM(OFS_PARM0);
1169 f = G_INT(OFS_PARM1);
1170 s = G_STRING(OFS_PARM2);
1173 RETURN_EDICT(sv.edicts);
1177 for (e++ ; e < sv.num_edicts ; e++)
1179 pr_xfunction->builtinsprofile++;
1193 RETURN_EDICT(sv.edicts);
1196 // LordHavoc: added this for searching float, int, and entity reference fields
1197 void PF_FindFloat (void)
1204 e = G_EDICTNUM(OFS_PARM0);
1205 f = G_INT(OFS_PARM1);
1206 s = G_FLOAT(OFS_PARM2);
1208 for (e++ ; e < sv.num_edicts ; e++)
1210 pr_xfunction->builtinsprofile++;
1214 if (E_FLOAT(ed,f) == s)
1221 RETURN_EDICT(sv.edicts);
1224 // chained search for strings in entity fields
1225 // entity(.string field, string match) findchain = #402;
1226 void PF_findchain (void)
1231 edict_t *ent, *chain;
1233 chain = (edict_t *)sv.edicts;
1235 f = G_INT(OFS_PARM0);
1236 s = G_STRING(OFS_PARM1);
1239 RETURN_EDICT(sv.edicts);
1243 ent = NEXT_EDICT(sv.edicts);
1244 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1246 pr_xfunction->builtinsprofile++;
1249 t = E_STRING(ent,f);
1255 ent->v->chain = EDICT_TO_PROG(chain);
1259 RETURN_EDICT(chain);
1262 // LordHavoc: chained search for float, int, and entity reference fields
1263 // entity(.string field, float match) findchainfloat = #403;
1264 void PF_findchainfloat (void)
1269 edict_t *ent, *chain;
1271 chain = (edict_t *)sv.edicts;
1273 f = G_INT(OFS_PARM0);
1274 s = G_FLOAT(OFS_PARM1);
1276 ent = NEXT_EDICT(sv.edicts);
1277 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1279 pr_xfunction->builtinsprofile++;
1282 if (E_FLOAT(ent,f) != s)
1285 ent->v->chain = EDICT_TO_PROG(chain);
1289 RETURN_EDICT(chain);
1292 // LordHavoc: search for flags in float fields
1293 void PF_findflags (void)
1300 e = G_EDICTNUM(OFS_PARM0);
1301 f = G_INT(OFS_PARM1);
1302 s = (int)G_FLOAT(OFS_PARM2);
1304 for (e++ ; e < sv.num_edicts ; e++)
1306 pr_xfunction->builtinsprofile++;
1310 if ((int)E_FLOAT(ed,f) & s)
1317 RETURN_EDICT(sv.edicts);
1320 // LordHavoc: chained search for flags in float fields
1321 void PF_findchainflags (void)
1326 edict_t *ent, *chain;
1328 chain = (edict_t *)sv.edicts;
1330 f = G_INT(OFS_PARM0);
1331 s = (int)G_FLOAT(OFS_PARM1);
1333 ent = NEXT_EDICT(sv.edicts);
1334 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1336 pr_xfunction->builtinsprofile++;
1339 if (!((int)E_FLOAT(ent,f) & s))
1342 ent->v->chain = EDICT_TO_PROG(chain);
1346 RETURN_EDICT(chain);
1349 void PR_CheckEmptyString (char *s)
1352 PF_ERROR("Bad string");
1355 void PF_precache_file (void)
1356 { // precache_file is only used to copy files with qcc, it does nothing
1357 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1360 void PF_precache_sound (void)
1364 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
1366 if (sv.state != ss_loading)
1367 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1369 s = G_STRING(OFS_PARM0);
1370 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1371 PR_CheckEmptyString (s);
1373 for (i=0 ; i<limit ; i++)
1375 if (!sv.sound_precache[i])
1377 sv.sound_precache[i] = s;
1380 if (!strcmp(sv.sound_precache[i], s))
1383 PF_ERROR("PF_precache_sound: overflow");
1386 void PF_precache_model (void)
1390 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
1392 if (sv.state != ss_loading)
1393 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1395 s = G_STRING(OFS_PARM0);
1396 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1398 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1399 PR_CheckEmptyString (s);
1401 for (i = 0;i < limit;i++)
1403 if (!sv.model_precache[i])
1405 sv.model_precache[i] = s;
1406 sv.models[i] = Mod_ForName (s, true, false, false);
1409 if (!strcmp(sv.model_precache[i], s))
1412 PF_ERROR("PF_precache_model: overflow");
1416 void PF_coredump (void)
1421 void PF_traceon (void)
1426 void PF_traceoff (void)
1431 void PF_eprint (void)
1433 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1440 float(float yaw, float dist) walkmove
1443 void PF_walkmove (void)
1451 // assume failure if it returns early
1452 G_FLOAT(OFS_RETURN) = 0;
1454 ent = PROG_TO_EDICT(pr_global_struct->self);
1455 if (ent == sv.edicts)
1456 PF_WARNING("walkmove: can not modify world entity\n");
1458 PF_WARNING("walkmove: can not modify free entity\n");
1459 yaw = G_FLOAT(OFS_PARM0);
1460 dist = G_FLOAT(OFS_PARM1);
1462 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1465 yaw = yaw*M_PI*2 / 360;
1467 move[0] = cos(yaw)*dist;
1468 move[1] = sin(yaw)*dist;
1471 // save program state, because SV_movestep may call other progs
1472 oldf = pr_xfunction;
1473 oldself = pr_global_struct->self;
1475 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1478 // restore program state
1479 pr_xfunction = oldf;
1480 pr_global_struct->self = oldself;
1490 void PF_droptofloor (void)
1496 // assume failure if it returns early
1497 G_FLOAT(OFS_RETURN) = 0;
1499 ent = PROG_TO_EDICT(pr_global_struct->self);
1500 if (ent == sv.edicts)
1501 PF_WARNING("droptofloor: can not modify world entity\n");
1503 PF_WARNING("droptofloor: can not modify free entity\n");
1505 VectorCopy (ent->v->origin, end);
1508 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1510 if (trace.fraction != 1)
1512 VectorCopy (trace.endpos, ent->v->origin);
1513 SV_LinkEdict (ent, false);
1514 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1515 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1516 G_FLOAT(OFS_RETURN) = 1;
1517 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1518 ent->e->suspendedinairflag = true;
1526 void(float style, string value) lightstyle
1529 void PF_lightstyle (void)
1536 style = G_FLOAT(OFS_PARM0);
1537 val = G_STRING(OFS_PARM1);
1539 // change the string in sv
1540 sv.lightstyles[style] = val;
1542 // send message to all clients on this server
1543 if (sv.state != ss_active)
1546 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1548 if (client->netconnection)
1550 MSG_WriteChar (&client->message, svc_lightstyle);
1551 MSG_WriteChar (&client->message,style);
1552 MSG_WriteString (&client->message, val);
1560 f = G_FLOAT(OFS_PARM0);
1562 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1564 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1566 void PF_floor (void)
1568 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1572 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1581 void PF_checkbottom (void)
1583 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1591 void PF_pointcontents (void)
1593 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1600 entity nextent(entity)
1603 void PF_nextent (void)
1608 i = G_EDICTNUM(OFS_PARM0);
1611 pr_xfunction->builtinsprofile++;
1613 if (i == sv.num_edicts)
1615 RETURN_EDICT(sv.edicts);
1631 Pick a vector for the player to shoot along
1632 vector aim(entity, missilespeed)
1637 edict_t *ent, *check, *bestent;
1638 vec3_t start, dir, end, bestdir;
1641 float dist, bestdist;
1644 // assume failure if it returns early
1645 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1646 // if sv_aim is so high it can't possibly accept anything, skip out early
1647 if (sv_aim.value >= 1)
1650 ent = G_EDICT(OFS_PARM0);
1651 if (ent == sv.edicts)
1652 PF_WARNING("aim: can not use world entity\n");
1654 PF_WARNING("aim: can not use free entity\n");
1655 speed = G_FLOAT(OFS_PARM1);
1657 VectorCopy (ent->v->origin, start);
1660 // try sending a trace straight
1661 VectorCopy (pr_global_struct->v_forward, dir);
1662 VectorMA (start, 2048, dir, end);
1663 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1664 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1665 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1667 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1672 // try all possible entities
1673 VectorCopy (dir, bestdir);
1674 bestdist = sv_aim.value;
1677 check = NEXT_EDICT(sv.edicts);
1678 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1680 pr_xfunction->builtinsprofile++;
1681 if (check->v->takedamage != DAMAGE_AIM)
1685 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1686 continue; // don't aim at teammate
1687 for (j=0 ; j<3 ; j++)
1688 end[j] = check->v->origin[j]
1689 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1690 VectorSubtract (end, start, dir);
1691 VectorNormalize (dir);
1692 dist = DotProduct (dir, pr_global_struct->v_forward);
1693 if (dist < bestdist)
1694 continue; // to far to turn
1695 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1696 if (tr.ent == check)
1697 { // can shoot at this one
1705 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1706 dist = DotProduct (dir, pr_global_struct->v_forward);
1707 VectorScale (pr_global_struct->v_forward, dist, end);
1709 VectorNormalize (end);
1710 VectorCopy (end, G_VECTOR(OFS_RETURN));
1714 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1722 This was a major timewaster in progs, so it was converted to C
1725 void PF_changeyaw (void)
1728 float ideal, current, move, speed;
1730 ent = PROG_TO_EDICT(pr_global_struct->self);
1731 if (ent == sv.edicts)
1732 PF_WARNING("changeyaw: can not modify world entity\n");
1734 PF_WARNING("changeyaw: can not modify free entity\n");
1735 current = ANGLEMOD(ent->v->angles[1]);
1736 ideal = ent->v->ideal_yaw;
1737 speed = ent->v->yaw_speed;
1739 if (current == ideal)
1741 move = ideal - current;
1742 if (ideal > current)
1763 ent->v->angles[1] = ANGLEMOD (current + move);
1771 void PF_changepitch (void)
1774 float ideal, current, move, speed;
1777 ent = G_EDICT(OFS_PARM0);
1778 if (ent == sv.edicts)
1779 PF_WARNING("changepitch: can not modify world entity\n");
1781 PF_WARNING("changepitch: can not modify free entity\n");
1782 current = ANGLEMOD( ent->v->angles[0] );
1783 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1784 ideal = val->_float;
1787 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1790 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1791 speed = val->_float;
1794 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1798 if (current == ideal)
1800 move = ideal - current;
1801 if (ideal > current)
1822 ent->v->angles[0] = ANGLEMOD (current + move);
1826 ===============================================================================
1830 ===============================================================================
1833 #define MSG_BROADCAST 0 // unreliable to all
1834 #define MSG_ONE 1 // reliable to one (msg_entity)
1835 #define MSG_ALL 2 // reliable to all
1836 #define MSG_INIT 3 // write to the init string
1838 sizebuf_t *WriteDest (void)
1844 dest = G_FLOAT(OFS_PARM0);
1848 return &sv.datagram;
1851 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1852 entnum = NUM_FOR_EDICT(ent);
1853 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1854 Host_Error("WriteDest: tried to write to non-client\n");
1855 return &svs.clients[entnum-1].message;
1858 return &sv.reliable_datagram;
1864 Host_Error("WriteDest: bad destination");
1871 void PF_WriteByte (void)
1873 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1876 void PF_WriteChar (void)
1878 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1881 void PF_WriteShort (void)
1883 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1886 void PF_WriteLong (void)
1888 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1891 void PF_WriteAngle (void)
1893 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1896 void PF_WriteCoord (void)
1898 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1901 void PF_WriteString (void)
1903 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1907 void PF_WriteEntity (void)
1909 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1912 //=============================================================================
1914 void PF_makestatic (void)
1919 ent = G_EDICT(OFS_PARM0);
1920 if (ent == sv.edicts)
1921 PF_WARNING("makestatic: can not modify world entity\n");
1923 PF_WARNING("makestatic: can not modify free entity\n");
1926 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1931 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1932 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1933 MSG_WriteShort (&sv.signon, ent->v->frame);
1937 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1938 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1939 MSG_WriteByte (&sv.signon, ent->v->frame);
1942 MSG_WriteByte (&sv.signon, ent->v->colormap);
1943 MSG_WriteByte (&sv.signon, ent->v->skin);
1944 for (i=0 ; i<3 ; i++)
1946 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1947 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1950 // throw the entity away now
1954 //=============================================================================
1961 void PF_setspawnparms (void)
1967 ent = G_EDICT(OFS_PARM0);
1968 i = NUM_FOR_EDICT(ent);
1969 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1971 Con_Print("tried to setspawnparms on a non-client\n");
1975 // copy spawn parms out of the client_t
1976 client = svs.clients + i-1;
1977 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1978 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1986 void PF_changelevel (void)
1990 // make sure we don't issue two changelevels
1991 if (svs.changelevel_issued)
1993 svs.changelevel_issued = true;
1995 s = G_STRING(OFS_PARM0);
1996 Cbuf_AddText (va("changelevel %s\n",s));
2001 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
2006 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
2011 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
2018 Returns a vector of length < 1
2023 void PF_randomvec (void)
2028 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2029 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2030 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2032 while (DotProduct(temp, temp) >= 1);
2033 VectorCopy (temp, G_VECTOR(OFS_RETURN));
2040 Returns a color vector indicating the lighting at the requested point.
2042 (Internal Operation note: actually measures the light beneath the point, just like
2043 the model lighting on the client)
2048 void PF_GetLight (void)
2050 vec3_t ambientcolor, diffusecolor, diffusenormal;
2052 p = G_VECTOR(OFS_PARM0);
2053 VectorClear(ambientcolor);
2054 VectorClear(diffusecolor);
2055 VectorClear(diffusenormal);
2056 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2057 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2058 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2061 void PF_registercvar (void)
2064 name = G_STRING(OFS_PARM0);
2065 value = G_STRING(OFS_PARM1);
2066 G_FLOAT(OFS_RETURN) = 0;
2068 // first check to see if it has already been defined
2069 if (Cvar_FindVar (name))
2072 // check for overlap with a command
2073 if (Cmd_Exists (name))
2075 Con_Printf("PF_registercvar: %s is a command\n", name);
2079 Cvar_Get(name, value, 0);
2081 G_FLOAT(OFS_RETURN) = 1; // success
2088 returns the minimum of two supplied floats
2095 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2097 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2098 else if (pr_argc >= 3)
2101 float f = G_FLOAT(OFS_PARM0);
2102 for (i = 1;i < pr_argc;i++)
2103 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2104 f = G_FLOAT((OFS_PARM0+i*3));
2105 G_FLOAT(OFS_RETURN) = f;
2109 G_FLOAT(OFS_RETURN) = 0;
2110 PF_WARNING("min: must supply at least 2 floats\n");
2118 returns the maximum of two supplied floats
2125 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2127 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2128 else if (pr_argc >= 3)
2131 float f = G_FLOAT(OFS_PARM0);
2132 for (i = 1;i < pr_argc;i++)
2133 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2134 f = G_FLOAT((OFS_PARM0+i*3));
2135 G_FLOAT(OFS_RETURN) = f;
2139 G_FLOAT(OFS_RETURN) = 0;
2140 PF_WARNING("max: must supply at least 2 floats\n");
2148 returns number bounded by supplied range
2150 min(min, value, max)
2153 void PF_bound (void)
2155 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2162 returns a raised to power b
2169 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2176 copies data from one entity to another
2178 copyentity(src, dst)
2181 void PF_copyentity (void)
2184 in = G_EDICT(OFS_PARM0);
2185 if (in == sv.edicts)
2186 PF_WARNING("copyentity: can not read world entity\n");
2188 PF_WARNING("copyentity: can not read free entity\n");
2189 out = G_EDICT(OFS_PARM1);
2190 if (out == sv.edicts)
2191 PF_WARNING("copyentity: can not modify world entity\n");
2193 PF_WARNING("copyentity: can not modify free entity\n");
2194 memcpy(out->v, in->v, progs->entityfields * 4);
2201 sets the color of a client and broadcasts the update to all connected clients
2203 setcolor(clientent, value)
2206 void PF_setcolor (void)
2212 entnum = G_EDICTNUM(OFS_PARM0);
2213 i = G_FLOAT(OFS_PARM1);
2215 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2217 Con_Print("tried to setcolor a non-client\n");
2221 client = svs.clients + entnum-1;
2224 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2226 client->edict->v->team = (i & 15) + 1;
2229 if (client->old_colors != client->colors)
2231 client->old_colors = client->colors;
2232 // send notification to all clients
2233 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2234 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2235 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2243 effect(origin, modelname, startframe, framecount, framerate)
2246 void PF_effect (void)
2250 s = G_STRING(OFS_PARM1);
2252 PF_WARNING("effect: no model specified\n");
2254 i = SV_ModelIndex(s);
2256 PF_WARNING("effect: model not precached\n");
2257 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2260 void PF_te_blood (void)
2262 if (G_FLOAT(OFS_PARM2) < 1)
2264 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2265 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2267 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2268 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2271 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2272 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2273 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2275 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2278 void PF_te_bloodshower (void)
2280 if (G_FLOAT(OFS_PARM3) < 1)
2282 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2283 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2285 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2287 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2290 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2291 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2293 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2295 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2298 void PF_te_explosionrgb (void)
2300 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2301 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2303 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2305 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2307 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2308 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2309 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2312 void PF_te_particlecube (void)
2314 if (G_FLOAT(OFS_PARM3) < 1)
2316 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2317 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2319 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2320 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2321 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2324 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2325 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2331 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2333 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2334 // gravity true/false
2335 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2337 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2340 void PF_te_particlerain (void)
2342 if (G_FLOAT(OFS_PARM3) < 1)
2344 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2345 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2347 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2348 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2349 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2351 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2352 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2353 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2355 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2356 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2357 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2359 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2361 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2364 void PF_te_particlesnow (void)
2366 if (G_FLOAT(OFS_PARM3) < 1)
2368 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2369 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2371 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2372 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2373 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2375 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2376 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2377 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2381 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2383 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2385 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2388 void PF_te_spark (void)
2390 if (G_FLOAT(OFS_PARM2) < 1)
2392 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2393 MSG_WriteByte(&sv.datagram, TE_SPARK);
2395 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2396 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2397 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2399 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2400 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2401 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2403 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2406 void PF_te_gunshotquad (void)
2408 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2409 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2411 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2412 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2413 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2416 void PF_te_spikequad (void)
2418 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2419 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2421 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2422 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2423 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2426 void PF_te_superspikequad (void)
2428 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2429 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2431 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2432 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2433 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2436 void PF_te_explosionquad (void)
2438 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2439 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2441 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2442 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2443 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2446 void PF_te_smallflash (void)
2448 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2449 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2451 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2452 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2453 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2456 void PF_te_customflash (void)
2458 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2460 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2461 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2463 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2464 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2465 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2467 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2469 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2471 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2472 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2473 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2476 void PF_te_gunshot (void)
2478 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2479 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2481 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2482 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2483 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2486 void PF_te_spike (void)
2488 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2489 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2491 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2492 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2493 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2496 void PF_te_superspike (void)
2498 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2499 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2501 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2502 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2503 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2506 void PF_te_explosion (void)
2508 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2509 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2511 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2512 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2513 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2516 void PF_te_tarexplosion (void)
2518 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2519 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2521 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2522 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2523 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2526 void PF_te_wizspike (void)
2528 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2529 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2531 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2532 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2533 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2536 void PF_te_knightspike (void)
2538 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2539 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2541 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2542 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2543 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2546 void PF_te_lavasplash (void)
2548 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2549 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2551 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2552 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2553 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2556 void PF_te_teleport (void)
2558 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2559 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2561 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2562 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2563 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2566 void PF_te_explosion2 (void)
2568 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2569 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2571 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2572 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2573 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2575 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2576 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2579 void PF_te_lightning1 (void)
2581 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2582 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2584 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2586 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2587 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2588 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2591 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2592 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2595 void PF_te_lightning2 (void)
2597 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2598 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2600 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2602 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2603 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2604 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2606 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2607 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2608 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2611 void PF_te_lightning3 (void)
2613 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2614 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2616 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2618 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2619 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2620 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2622 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2623 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2624 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2627 void PF_te_beam (void)
2629 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2630 MSG_WriteByte(&sv.datagram, TE_BEAM);
2632 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2634 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2635 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2636 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2638 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2639 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2640 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2643 void PF_te_plasmaburn (void)
2645 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2646 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2647 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2648 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2649 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2652 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2655 vec3_t v1, clipplanenormal, normal;
2656 vec_t clipplanedist, clipdist;
2658 if (surf->flags & SURF_PLANEBACK)
2659 VectorNegate(surf->plane->normal, normal);
2661 VectorCopy(surf->plane->normal, normal);
2662 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2664 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2665 VectorNormalizeFast(v1);
2666 CrossProduct(v1, normal, clipplanenormal);
2667 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2668 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2671 clipdist = -clipdist;
2672 VectorMA(out, clipdist, clipplanenormal, out);
2677 static msurface_t *getsurface(edict_t *ed, int surfnum)
2681 if (!ed || ed->e->free)
2683 modelindex = ed->v->modelindex;
2684 if (modelindex < 1 || modelindex >= MAX_MODELS)
2686 model = sv.models[modelindex];
2687 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2689 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2693 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2694 void PF_getsurfacenumpoints(void)
2697 // return 0 if no such surface
2698 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2700 G_FLOAT(OFS_RETURN) = 0;
2704 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2706 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2707 void PF_getsurfacepoint(void)
2712 VectorClear(G_VECTOR(OFS_RETURN));
2713 ed = G_EDICT(OFS_PARM0);
2714 if (!ed || ed->e->free)
2716 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2718 pointnum = G_FLOAT(OFS_PARM2);
2719 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2721 // FIXME: implement rotation/scaling
2722 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2724 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2725 void PF_getsurfacenormal(void)
2728 VectorClear(G_VECTOR(OFS_RETURN));
2729 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2731 // FIXME: implement rotation/scaling
2732 if (surf->flags & SURF_PLANEBACK)
2733 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2735 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2737 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2738 void PF_getsurfacetexture(void)
2741 G_INT(OFS_RETURN) = 0;
2742 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2744 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2746 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2747 void PF_getsurfacenearpoint(void)
2749 int surfnum, best, modelindex;
2751 vec_t dist, bestdist;
2756 G_FLOAT(OFS_RETURN) = -1;
2757 ed = G_EDICT(OFS_PARM0);
2758 point = G_VECTOR(OFS_PARM1);
2760 if (!ed || ed->e->free)
2762 modelindex = ed->v->modelindex;
2763 if (modelindex < 1 || modelindex >= MAX_MODELS)
2765 model = sv.models[modelindex];
2766 if (!model->brushq1.numsurfaces)
2769 // FIXME: implement rotation/scaling
2770 VectorSubtract(point, ed->v->origin, p);
2772 bestdist = 1000000000;
2773 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2775 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2776 dist = PlaneDiff(p, surf->plane);
2778 if (dist < bestdist)
2780 clippointtosurface(surf, p, clipped);
2781 VectorSubtract(clipped, p, clipped);
2782 dist += DotProduct(clipped, clipped);
2783 if (dist < bestdist)
2790 G_FLOAT(OFS_RETURN) = best;
2792 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2793 void PF_getsurfaceclippedpoint(void)
2798 VectorClear(G_VECTOR(OFS_RETURN));
2799 ed = G_EDICT(OFS_PARM0);
2800 if (!ed || ed->e->free)
2802 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2804 // FIXME: implement rotation/scaling
2805 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2806 clippointtosurface(surf, p, out);
2807 // FIXME: implement rotation/scaling
2808 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2811 #define MAX_PRFILES 256
2813 qfile_t *pr_files[MAX_PRFILES];
2815 void PR_Files_Init(void)
2817 memset(pr_files, 0, sizeof(pr_files));
2820 void PR_Files_CloseAll(void)
2823 for (i = 0;i < MAX_PRFILES;i++)
2826 FS_Close(pr_files[i]);
2831 //float(string s) stof = #81; // get numerical value from a string
2834 char string[STRINGTEMP_LENGTH];
2835 PF_VarString(0, string, sizeof(string));
2836 G_FLOAT(OFS_RETURN) = atof(string);
2839 //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
2842 int filenum, mode, i;
2843 char *modestring, *filename;
2844 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2845 if (pr_files[filenum] == NULL)
2847 if (filenum >= MAX_PRFILES)
2849 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2850 G_FLOAT(OFS_RETURN) = -2;
2853 mode = G_FLOAT(OFS_PARM1);
2856 case 0: // FILE_READ
2859 case 1: // FILE_APPEND
2862 case 2: // FILE_WRITE
2866 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2867 G_FLOAT(OFS_RETURN) = -3;
2870 filename = G_STRING(OFS_PARM0);
2871 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2872 // ../ is parent directory on many platforms
2873 // // is parent directory on Amiga
2874 // / at the beginning of a path is root on unix, and parent directory on Amiga
2875 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2876 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2877 for (i = 0;filename[i];i++)
2879 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2881 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);
2882 G_FLOAT(OFS_RETURN) = -4;
2886 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2888 if (pr_files[filenum] == NULL && modestring == "rb")
2889 pr_files[filenum] = FS_Open(filename, modestring, false);
2891 if (pr_files[filenum] == NULL)
2892 G_FLOAT(OFS_RETURN) = -1;
2894 G_FLOAT(OFS_RETURN) = filenum;
2897 //void(float fhandle) fclose = #111; // closes a file
2898 void PF_fclose(void)
2900 int filenum = G_FLOAT(OFS_PARM0);
2901 if (filenum < 0 || filenum >= MAX_PRFILES)
2903 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2906 if (pr_files[filenum] == NULL)
2908 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2911 FS_Close(pr_files[filenum]);
2912 pr_files[filenum] = NULL;
2915 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2919 static char string[STRINGTEMP_LENGTH];
2920 int filenum = G_FLOAT(OFS_PARM0);
2921 if (filenum < 0 || filenum >= MAX_PRFILES)
2923 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2926 if (pr_files[filenum] == NULL)
2928 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2934 c = FS_Getc(pr_files[filenum]);
2935 if (c == '\r' || c == '\n' || c < 0)
2937 if (end < STRINGTEMP_LENGTH - 1)
2941 // remove \n following \r
2943 c = FS_Getc(pr_files[filenum]);
2944 if (developer.integer)
2945 Con_Printf("fgets: %s\n", string);
2947 G_INT(OFS_RETURN) = PR_SetString(string);
2949 G_INT(OFS_RETURN) = 0;
2952 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2956 char string[STRINGTEMP_LENGTH];
2957 int filenum = G_FLOAT(OFS_PARM0);
2958 if (filenum < 0 || filenum >= MAX_PRFILES)
2960 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2963 if (pr_files[filenum] == NULL)
2965 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2968 PF_VarString(1, string, sizeof(string));
2969 if ((stringlength = strlen(string)))
2970 FS_Write(pr_files[filenum], string, stringlength);
2971 if (developer.integer)
2972 Con_Printf("fputs: %s\n", string);
2975 //float(string s) strlen = #114; // returns how many characters are in a string
2976 void PF_strlen(void)
2979 s = G_STRING(OFS_PARM0);
2981 G_FLOAT(OFS_RETURN) = strlen(s);
2983 G_FLOAT(OFS_RETURN) = 0;
2986 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2987 void PF_strcat(void)
2989 char *s = PR_GetTempString();
2990 PF_VarString(0, s, STRINGTEMP_LENGTH);
2991 G_INT(OFS_RETURN) = PR_SetString(s);
2994 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2995 void PF_substring(void)
2997 int i, start, length;
2998 char *s, *string = PR_GetTempString();
2999 s = G_STRING(OFS_PARM0);
3000 start = G_FLOAT(OFS_PARM1);
3001 length = G_FLOAT(OFS_PARM2);
3004 for (i = 0;i < start && *s;i++, s++);
3005 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3008 G_INT(OFS_RETURN) = PR_SetString(string);
3011 //vector(string s) stov = #117; // returns vector value from a string
3014 char string[STRINGTEMP_LENGTH];
3015 PF_VarString(0, string, sizeof(string));
3016 Math_atov(string, G_VECTOR(OFS_RETURN));
3019 //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)
3020 void PF_strzone(void)
3023 in = G_STRING(OFS_PARM0);
3024 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3026 G_INT(OFS_RETURN) = PR_SetString(out);
3029 //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!!!)
3030 void PF_strunzone(void)
3032 Mem_Free(G_STRING(OFS_PARM0));
3035 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3036 //this function originally written by KrimZon, made shorter by LordHavoc
3037 void PF_clientcommand (void)
3039 client_t *temp_client;
3042 //find client for this entity
3043 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3044 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3046 Con_Print("PF_clientcommand: entity is not a client\n");
3050 temp_client = host_client;
3051 host_client = svs.clients + i;
3052 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3053 host_client = temp_client;
3056 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3057 //this function originally written by KrimZon, made shorter by LordHavoc
3058 //20040203: rewritten by LordHavoc (no longer uses allocations)
3060 char *tokens[256], tokenbuf[4096];
3061 void PF_tokenize (void)
3065 p = G_STRING(OFS_PARM0);
3069 while(COM_ParseToken(&p, false))
3071 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3073 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3075 tokens[num_tokens++] = tokenbuf + pos;
3076 strcpy(tokenbuf + pos, com_token);
3077 pos += strlen(com_token) + 1;
3080 G_FLOAT(OFS_RETURN) = num_tokens;
3083 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3084 //this function originally written by KrimZon, made shorter by LordHavoc
3087 int token_num = G_FLOAT(OFS_PARM0);
3088 if (token_num >= 0 && token_num < num_tokens)
3089 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3091 G_INT(OFS_RETURN) = PR_SetString("");
3094 //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)
3095 void PF_setattachment (void)
3097 edict_t *e = G_EDICT(OFS_PARM0);
3098 edict_t *tagentity = G_EDICT(OFS_PARM1);
3099 char *tagname = G_STRING(OFS_PARM2);
3105 PF_WARNING("setattachment: can not modify world entity\n");
3107 PF_WARNING("setattachment: can not modify free entity\n");
3109 if (tagentity == NULL)
3110 tagentity = sv.edicts;
3112 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3114 v->edict = EDICT_TO_PROG(tagentity);
3116 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3119 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3121 modelindex = (int)tagentity->v->modelindex;
3122 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3124 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3125 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3126 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3128 // FIXME: use a model function to get tag info (need to handle skeletal)
3129 if (v->_float == 0 && model->alias.aliasnum_tags)
3130 for (i = 0;i < model->alias.aliasnum_tags;i++)
3131 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3134 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);
3137 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));
3141 /////////////////////////////////////////
3142 // DP_MD3_TAGINFO extension coded by VorteX
3144 //float(entity ent, string tagname) gettagindex;
3145 void PF_gettagindex (void)
3147 edict_t *e = G_EDICT(OFS_PARM0);
3148 const char *tagname = G_STRING(OFS_PARM1);
3149 int modelindex, tagindex, i;
3153 PF_WARNING("gettagindex: can't affect world entity\n");
3155 PF_WARNING("gettagindex: can't affect free entity\n");
3157 modelindex = (int)e->v->modelindex;
3158 if (modelindex <= 0 || modelindex > MAX_MODELS)
3160 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3163 model = sv.models[modelindex];
3166 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3168 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3170 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3179 for (i = 0;i < model->alias.aliasnum_tags; i++)
3181 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3189 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(e), tagname);
3190 G_FLOAT(OFS_RETURN) = tagindex + 1;
3193 // Warnings/errors code:
3194 // 0 - normal (everything all-right)
3197 // 3 - null or non-precached model
3198 // 4 - no tags with requested index
3199 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3203 int modelindex, tagsnum, reqframe;
3204 matrix4x4_t entitymatrix, tagmatrix;
3207 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3209 if (ent == sv.edicts)
3214 modelindex = (int)ent->v->modelindex;
3215 if (modelindex <= 0 || modelindex > MAX_MODELS)
3218 model = sv.models[modelindex];
3219 tagsnum = model->alias.aliasnum_tags;
3221 if (tagindex <= 0 || tagindex > tagsnum)
3223 if (tagsnum && tagindex) // Only appear if model has no tags or not-null tag requested
3228 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3229 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3231 reqframe = ent->v->frame;
3233 // just reusing a temp
3234 modelindex = (tagindex - 1) + ent->v->frame*tagsnum;
3236 // transform tag by its own entity matrix
3237 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[modelindex].matrix);
3238 // FIXME: add scale parameter
3240 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3241 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], -ent->v->angles[0], ent->v->angles[1], ent->v->angles[2], scale);
3242 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3243 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3244 out->m[0][3] = entitymatrix.m[0][3] + entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3];
3245 out->m[1][3] = entitymatrix.m[1][3] + entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3];
3246 out->m[2][3] = entitymatrix.m[2][3] + entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3];
3248 // additional actions for render-view entities
3249 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3250 {// RENDER_VIEWMODEL
3251 Matrix4x4_Copy(&tagmatrix, out);
3252 ent = EDICT_NUM(val->edict);
3253 // FIXME: add bobbing (cl_bob), add scale parameter
3255 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] + ent->v->view_ofs[2], ent->v->v_angle[0], ent->v->v_angle[1], ent->v->v_angle[2], scale);
3256 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3257 out->m[0][3] = entitymatrix.m[0][3] + entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3];
3258 out->m[1][3] = entitymatrix.m[1][3] + entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3];
3259 out->m[2][3] = entitymatrix.m[2][3] + entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3];
3260 Con_DPrintf("SV_GetTagMatrix: returned origin is %f %f %f\n", out->m[0][3], out->m[1][3], out->m[2][3]);
3263 // RENDER_VIEWMODEL can't be attached by tag, right?
3264 val = GETEDICTFIELDVALUE(ent, eval_tag_entity);
3266 {// DP_GFX_QUAKE3MODELTAGS
3269 ent = EDICT_NUM(val->edict);
3270 // FIXME: add scale parameter
3271 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], -ent->v->angles[0], ent->v->angles[1], ent->v->angles[2], scale);
3272 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3273 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3274 out->m[0][3] = entitymatrix.m[0][3] + entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3];
3275 out->m[1][3] = entitymatrix.m[1][3] + entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3];
3276 out->m[2][3] = entitymatrix.m[2][3] + entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3];
3279 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3284 //vector(entity ent, float tagindex) gettaginfo;
3285 void PF_gettaginfo (void)
3287 edict_t *e = G_EDICT(OFS_PARM0);
3288 int tagindex = (int)G_FLOAT(OFS_PARM1);
3289 matrix4x4_t tag_matrix;
3292 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3293 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3298 PF_WARNING("gettagindex: can't affect world entity\n");
3301 PF_WARNING("gettagindex: can't affect free entity\n");
3304 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3307 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3313 /////////////////////////////////////////
3314 // DP_QC_FS_SEARCH extension
3316 // qc fs search handling
3317 #define MAX_SEARCHES 128
3319 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3321 void PR_Search_Init(void)
3323 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3326 void PR_Search_Reset(void)
3329 // reset the fssearch list
3330 for(i = 0; i < MAX_SEARCHES; i++)
3331 if(pr_fssearchlist[i])
3332 FS_FreeSearch(pr_fssearchlist[i]);
3333 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3340 float search_begin(string pattern, float caseinsensitive, float quiet)
3343 void PF_search_begin(void)
3347 int caseinsens, quiet;
3349 pattern = G_STRING(OFS_PARM0);
3351 PR_CheckEmptyString(pattern);
3353 caseinsens = G_FLOAT(OFS_PARM1);
3354 quiet = G_FLOAT(OFS_PARM2);
3356 for(handle = 0; handle < MAX_SEARCHES; handle++)
3357 if(!pr_fssearchlist[handle])
3360 if(handle >= MAX_SEARCHES)
3362 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3363 G_FLOAT(OFS_RETURN) = -2;
3367 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3368 G_FLOAT(OFS_RETURN) = -1;
3370 G_FLOAT(OFS_RETURN) = handle;
3377 void search_end(float handle)
3380 void PF_search_end(void)
3384 handle = G_FLOAT(OFS_PARM0);
3386 if(handle < 0 || handle >= MAX_SEARCHES)
3388 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3391 if(pr_fssearchlist[handle] == NULL)
3393 Con_Printf("PF_search_end: no such handle %i\n", handle);
3397 FS_FreeSearch(pr_fssearchlist[handle]);
3398 pr_fssearchlist[handle] = NULL;
3405 float search_getsize(float handle)
3408 void PF_search_getsize(void)
3412 handle = G_FLOAT(OFS_PARM0);
3414 if(handle < 0 || handle >= MAX_SEARCHES)
3416 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3419 if(pr_fssearchlist[handle] == NULL)
3421 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3425 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3430 VM_search_getfilename
3432 string search_getfilename(float handle, float num)
3435 void PF_search_getfilename(void)
3437 int handle, filenum;
3440 handle = G_FLOAT(OFS_PARM0);
3441 filenum = G_FLOAT(OFS_PARM1);
3443 if(handle < 0 || handle >= MAX_SEARCHES)
3445 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3448 if(pr_fssearchlist[handle] == NULL)
3450 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3453 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3455 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3459 tmp = PR_GetTempString();
3460 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3462 G_INT(OFS_RETURN) = PR_SetString(tmp);
3465 void PF_cvar_string (void)
3471 str = G_STRING(OFS_PARM0);
3472 var = Cvar_FindVar (str);
3475 tmp = PR_GetTempString();
3476 strcpy(tmp, var->string);
3480 G_INT(OFS_RETURN) = PR_SetString(tmp);
3483 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3484 void PF_dropclient (void)
3487 client_t *oldhostclient;
3488 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3489 if (clientnum < 0 || clientnum >= svs.maxclients)
3490 PF_WARNING("dropclient: not a client\n");
3491 if (!svs.clients[clientnum].active)
3492 PF_WARNING("dropclient: that client slot is not connected\n");
3493 oldhostclient = host_client;
3494 host_client = svs.clients + clientnum;
3495 SV_DropClient(false);
3496 host_client = oldhostclient;
3500 builtin_t pr_builtin[] =
3503 PF_makevectors, // #1 void(entity e) makevectors
3504 PF_setorigin, // #2 void(entity e, vector o) setorigin
3505 PF_setmodel, // #3 void(entity e, string m) setmodel
3506 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3507 NULL, // #5 void(entity e, vector min, vector max) setabssize
3508 PF_break, // #6 void() break
3509 PF_random, // #7 float() random
3510 PF_sound, // #8 void(entity e, float chan, string samp) sound
3511 PF_normalize, // #9 vector(vector v) normalize
3512 PF_error, // #10 void(string e) error
3513 PF_objerror, // #11 void(string e) objerror
3514 PF_vlen, // #12 float(vector v) vlen
3515 PF_vectoyaw, // #13 float(vector v) vectoyaw
3516 PF_Spawn, // #14 entity() spawn
3517 PF_Remove, // #15 void(entity e) remove
3518 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3519 PF_checkclient, // #17 entity() clientlist
3520 PF_Find, // #18 entity(entity start, .string fld, string match) find
3521 PF_precache_sound, // #19 void(string s) precache_sound
3522 PF_precache_model, // #20 void(string s) precache_model
3523 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3524 PF_findradius, // #22 entity(vector org, float rad) findradius
3525 PF_bprint, // #23 void(string s) bprint
3526 PF_sprint, // #24 void(entity client, string s) sprint
3527 PF_dprint, // #25 void(string s) dprint
3528 PF_ftos, // #26 void(string s) ftos
3529 PF_vtos, // #27 void(string s) vtos
3530 PF_coredump, // #28 void() coredump
3531 PF_traceon, // #29 void() traceon
3532 PF_traceoff, // #30 void() traceoff
3533 PF_eprint, // #31 void(entity e) eprint
3534 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3536 PF_droptofloor, // #34 float() droptofloor
3537 PF_lightstyle, // #35 void(float style, string value) lightstyle
3538 PF_rint, // #36 float(float v) rint
3539 PF_floor, // #37 float(float v) floor
3540 PF_ceil, // #38 float(float v) ceil
3542 PF_checkbottom, // #40 float(entity e) checkbottom
3543 PF_pointcontents , // #41 float(vector v) pointcontents
3545 PF_fabs, // #43 float(float f) fabs
3546 PF_aim, // #44 vector(entity e, float speed) aim
3547 PF_cvar, // #45 float(string s) cvar
3548 PF_localcmd, // #46 void(string s) localcmd
3549 PF_nextent, // #47 entity(entity e) nextent
3550 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3551 PF_changeyaw, // #49 void() ChangeYaw
3553 PF_vectoangles, // #51 vector(vector v) vectoangles
3554 PF_WriteByte, // #52 void(float to, float f) WriteByte
3555 PF_WriteChar, // #53 void(float to, float f) WriteChar
3556 PF_WriteShort, // #54 void(float to, float f) WriteShort
3557 PF_WriteLong, // #55 void(float to, float f) WriteLong
3558 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3559 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3560 PF_WriteString, // #58 void(float to, string s) WriteString
3561 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3562 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3563 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3564 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3565 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3566 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3567 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3569 SV_MoveToGoal, // #67 void(float step) movetogoal
3570 PF_precache_file, // #68 string(string s) precache_file
3571 PF_makestatic, // #69 void(entity e) makestatic
3572 PF_changelevel, // #70 void(string s) changelevel
3574 PF_cvar_set, // #72 void(string var, string val) cvar_set
3575 PF_centerprint, // #73 void(entity client, strings) centerprint
3576 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3577 PF_precache_model, // #75 string(string s) precache_model2
3578 PF_precache_sound, // #76 string(string s) precache_sound2
3579 PF_precache_file, // #77 string(string s) precache_file2
3580 PF_setspawnparms, // #78 void(entity e) setspawnparms
3583 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3592 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3593 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3594 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3595 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3596 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3597 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3598 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3599 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3600 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3601 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3612 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3613 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3614 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3615 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3616 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3617 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3618 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3619 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3620 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3621 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3622 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3623 a a a a a a a a // #120-199
3624 a a a a a a a a a a // #200-299
3625 a a a a a a a a a a // #300-399
3626 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3627 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3628 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3629 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3630 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3631 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3632 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3633 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3634 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3635 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3636 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3637 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3638 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3639 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3640 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3641 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3642 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3643 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3644 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3645 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3646 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3647 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3648 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3649 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3650 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3651 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3652 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3653 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3654 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3655 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3656 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3657 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3658 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3659 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3660 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3661 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3662 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3663 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3664 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3665 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3666 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3667 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3668 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3669 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3670 PF_search_begin, // #444
3671 PF_search_end, // #445
3672 PF_search_getsize, // #446
3673 PF_search_getfilename, // #447
3674 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3675 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3676 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3677 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3678 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3679 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3686 a a a a // #460-499 (LordHavoc)
3689 builtin_t *pr_builtins = pr_builtin;
3690 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3692 void PR_Cmd_Init(void)
3694 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3699 void PR_Cmd_Reset(void)
3701 Mem_EmptyPool(pr_strings_mempool);
3703 PR_Files_CloseAll();