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 =
86 "DP_ENT_CUSTOMCOLORMAP "
87 "DP_ENT_EXTERIORMODELTOCLIENT "
89 "DP_ENT_LOWPRECISION "
92 "DP_GFX_EXTERNALTEXTURES "
94 "DP_GFX_QUAKE3MODELTAGS "
98 "DP_HALFLIFE_MAP_CVAR "
103 "DP_MOVETYPEBOUNCEMISSILE "
110 "DP_QC_FINDCHAINFLAGS "
111 "DP_QC_FINDCHAINFLOAT "
114 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
119 "DP_QC_MULTIPLETEMPSTRINGS "
121 "DP_QC_SINCOSSQRTPOW "
124 "DP_QC_TRACE_MOVETYPE_HITMODEL "
125 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
126 "DP_QC_VECTORVECTORS "
130 "DP_SND_DIRECTIONLESSATTNNONE "
136 "DP_SV_DRAWONLYTOCLIENT "
139 "DP_SV_NODRAWTOCLIENT "
141 "DP_SV_PLAYERPHYSICS "
143 "DP_SV_ROTATINGBMODEL "
149 "DP_TE_EXPLOSIONRGB "
151 "DP_TE_PARTICLECUBE "
152 "DP_TE_PARTICLERAIN "
153 "DP_TE_PARTICLESNOW "
155 "DP_TE_QUADEFFECTS1 "
158 "DP_TE_STANDARDEFFECTBUILTINS "
161 "KRIMZON_SV_PARSECLIENTCOMMAND "
165 "TENEBRAE_GFX_DLIGHTS "
169 qboolean checkextension(char *name)
174 for (e = ENGINE_EXTENSIONS;*e;e++)
181 while (*e && *e != ' ')
183 if (e - start == len)
184 if (!strncasecmp(start, name, len))
194 returns true if the extension is supported by the server
196 checkextension(extensionname)
199 void PF_checkextension (void)
201 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
208 This is a TERMINAL error, which will kill off the entire server.
217 char string[STRINGTEMP_LENGTH];
219 PF_VarString(0, string, sizeof(string));
220 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
221 ed = PROG_TO_EDICT(pr_global_struct->self);
224 PF_ERROR("Program error");
231 Dumps out self, then an error message. The program is aborted and self is
232 removed, but the level can continue.
237 void PF_objerror (void)
240 char string[STRINGTEMP_LENGTH];
242 PF_VarString(0, string, sizeof(string));
243 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
244 ed = PROG_TO_EDICT(pr_global_struct->self);
254 Writes new values for v_forward, v_up, and v_right based on angles
258 void PF_makevectors (void)
260 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
267 Writes new values for v_forward, v_up, and v_right based on the given forward vector
268 vectorvectors(vector, vector)
271 void PF_vectorvectors (void)
273 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
274 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
281 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.
283 setorigin (entity, origin)
286 void PF_setorigin (void)
291 e = G_EDICT(OFS_PARM0);
293 PF_WARNING("setorigin: can not modify world entity\n");
295 PF_WARNING("setorigin: can not modify free entity\n");
296 org = G_VECTOR(OFS_PARM1);
297 VectorCopy (org, e->v->origin);
298 SV_LinkEdict (e, false);
302 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
306 for (i=0 ; i<3 ; i++)
308 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
310 // set derived values
311 VectorCopy (min, e->v->mins);
312 VectorCopy (max, e->v->maxs);
313 VectorSubtract (max, min, e->v->size);
315 SV_LinkEdict (e, false);
322 the size box is rotated by the current angle
323 LordHavoc: no it isn't...
325 setsize (entity, minvector, maxvector)
328 void PF_setsize (void)
333 e = G_EDICT(OFS_PARM0);
335 PF_WARNING("setsize: can not modify world entity\n");
337 PF_WARNING("setsize: can not modify free entity\n");
338 min = G_VECTOR(OFS_PARM1);
339 max = G_VECTOR(OFS_PARM2);
340 SetMinMaxSize (e, min, max, false);
348 setmodel(entity, model)
351 void PF_setmodel (void)
358 e = G_EDICT(OFS_PARM0);
360 PF_WARNING("setmodel: can not modify world entity\n");
362 PF_WARNING("setmodel: can not modify free entity\n");
363 m = G_STRING(OFS_PARM1);
365 // check to see if model was properly precached
366 for (i=0, check = sv.model_precache ; *check ; i++, check++)
367 if (!strcmp(*check, m))
371 PF_WARNING(va("setmodel: no precache for model \"%s\"\n", m));
374 e->v->model = PR_SetString(*check);
375 e->v->modelindex = i;
377 mod = sv.models[ (int)e->v->modelindex];
380 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
382 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
389 broadcast print to everyone on server
394 void PF_bprint (void)
396 char string[STRINGTEMP_LENGTH];
397 PF_VarString(0, string, sizeof(string));
398 SV_BroadcastPrint(string);
405 single print to a specific client
407 sprint(clientent, value)
410 void PF_sprint (void)
414 char string[STRINGTEMP_LENGTH];
416 entnum = G_EDICTNUM(OFS_PARM0);
418 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
420 Con_Print("tried to sprint to a non-client\n");
424 client = svs.clients + entnum-1;
425 if (!client->netconnection)
427 PF_VarString(1, string, sizeof(string));
428 MSG_WriteChar(&client->message,svc_print);
429 MSG_WriteString(&client->message, string);
437 single print to a specific client
439 centerprint(clientent, value)
442 void PF_centerprint (void)
446 char string[STRINGTEMP_LENGTH];
448 entnum = G_EDICTNUM(OFS_PARM0);
450 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
452 Con_Print("tried to sprint to a non-client\n");
456 client = svs.clients + entnum-1;
457 if (!client->netconnection)
459 PF_VarString(1, string, sizeof(string));
460 MSG_WriteChar(&client->message,svc_centerprint);
461 MSG_WriteString(&client->message, string);
469 vector normalize(vector)
472 void PF_normalize (void)
478 value1 = G_VECTOR(OFS_PARM0);
480 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
484 newvalue[0] = newvalue[1] = newvalue[2] = 0;
488 newvalue[0] = value1[0] * new;
489 newvalue[1] = value1[1] * new;
490 newvalue[2] = value1[2] * new;
493 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
508 value1 = G_VECTOR(OFS_PARM0);
510 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
513 G_FLOAT(OFS_RETURN) = new;
520 float vectoyaw(vector)
523 void PF_vectoyaw (void)
528 value1 = G_VECTOR(OFS_PARM0);
530 if (value1[1] == 0 && value1[0] == 0)
534 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
539 G_FLOAT(OFS_RETURN) = yaw;
547 vector vectoangles(vector)
550 void PF_vectoangles (void)
552 double value1[3], forward, yaw, pitch;
554 VectorCopy(G_VECTOR(OFS_PARM0), value1);
556 if (value1[1] == 0 && value1[0] == 0)
566 // LordHavoc: optimized a bit
569 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
573 else if (value1[1] > 0)
578 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
579 pitch = (atan2(value1[2], forward) * 180 / M_PI);
584 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
591 Returns a number from 0<= num < 1
596 void PF_random (void)
600 num = (rand ()&0x7fff) / ((float)0x7fff);
602 G_FLOAT(OFS_RETURN) = num;
609 particle(origin, color, count)
612 void PF_particle (void)
618 org = G_VECTOR(OFS_PARM0);
619 dir = G_VECTOR(OFS_PARM1);
620 color = G_FLOAT(OFS_PARM2);
621 count = G_FLOAT(OFS_PARM3);
622 SV_StartParticle (org, dir, color, count);
632 void PF_ambientsound (void)
637 float vol, attenuation;
640 pos = G_VECTOR (OFS_PARM0);
641 samp = G_STRING(OFS_PARM1);
642 vol = G_FLOAT(OFS_PARM2);
643 attenuation = G_FLOAT(OFS_PARM3);
645 // check to see if samp was properly precached
646 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
647 if (!strcmp(*check,samp))
652 Con_Printf("no precache: %s\n", samp);
660 // add an svc_spawnambient command to the level signon packet
663 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
665 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
667 MSG_WriteVector(&sv.signon, pos, sv.protocol);
670 MSG_WriteShort (&sv.signon, soundnum);
672 MSG_WriteByte (&sv.signon, soundnum);
674 MSG_WriteByte (&sv.signon, vol*255);
675 MSG_WriteByte (&sv.signon, attenuation*64);
683 Each entity can have eight independant sound sources, like voice,
686 Channel 0 is an auto-allocate channel, the others override anything
687 already running on that entity/channel pair.
689 An attenuation of 0 will play full volume everywhere in the level.
690 Larger attenuations will drop off.
702 entity = G_EDICT(OFS_PARM0);
703 channel = G_FLOAT(OFS_PARM1);
704 sample = G_STRING(OFS_PARM2);
705 volume = G_FLOAT(OFS_PARM3) * 255;
706 attenuation = G_FLOAT(OFS_PARM4);
708 if (volume < 0 || volume > 255)
709 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
711 if (attenuation < 0 || attenuation > 4)
712 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
714 if (channel < 0 || channel > 7)
715 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
717 SV_StartSound (entity, channel, sample, volume, attenuation);
729 PF_ERROR("break: break statement\n");
736 Used for use tracing and shot targeting
737 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
738 if the tryents flag is set.
740 traceline (vector1, vector2, tryents)
743 void PF_traceline (void)
750 pr_xfunction->builtinsprofile += 30;
752 v1 = G_VECTOR(OFS_PARM0);
753 v2 = G_VECTOR(OFS_PARM1);
754 move = G_FLOAT(OFS_PARM2);
755 ent = G_EDICT(OFS_PARM3);
757 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
759 pr_global_struct->trace_allsolid = trace.allsolid;
760 pr_global_struct->trace_startsolid = trace.startsolid;
761 pr_global_struct->trace_fraction = trace.fraction;
762 pr_global_struct->trace_inwater = trace.inwater;
763 pr_global_struct->trace_inopen = trace.inopen;
764 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
765 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
766 pr_global_struct->trace_plane_dist = trace.plane.dist;
768 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
770 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
771 // FIXME: add trace_endcontents
779 Used for use tracing and shot targeting
780 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
781 if the tryents flag is set.
783 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
786 // LordHavoc: added this for my own use, VERY useful, similar to traceline
787 void PF_tracebox (void)
789 float *v1, *v2, *m1, *m2;
794 pr_xfunction->builtinsprofile += 30;
796 v1 = G_VECTOR(OFS_PARM0);
797 m1 = G_VECTOR(OFS_PARM1);
798 m2 = G_VECTOR(OFS_PARM2);
799 v2 = G_VECTOR(OFS_PARM3);
800 move = G_FLOAT(OFS_PARM4);
801 ent = G_EDICT(OFS_PARM5);
803 trace = SV_Move (v1, m1, m2, v2, move, ent);
805 pr_global_struct->trace_allsolid = trace.allsolid;
806 pr_global_struct->trace_startsolid = trace.startsolid;
807 pr_global_struct->trace_fraction = trace.fraction;
808 pr_global_struct->trace_inwater = trace.inwater;
809 pr_global_struct->trace_inopen = trace.inopen;
810 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
811 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
812 pr_global_struct->trace_plane_dist = trace.plane.dist;
814 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
816 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
819 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
820 void PF_TraceToss (void)
826 pr_xfunction->builtinsprofile += 600;
828 ent = G_EDICT(OFS_PARM0);
829 if (ent == sv.edicts)
830 PF_WARNING("tracetoss: can not use world entity\n");
831 ignore = G_EDICT(OFS_PARM1);
833 trace = SV_Trace_Toss (ent, ignore);
835 pr_global_struct->trace_allsolid = trace.allsolid;
836 pr_global_struct->trace_startsolid = trace.startsolid;
837 pr_global_struct->trace_fraction = trace.fraction;
838 pr_global_struct->trace_inwater = trace.inwater;
839 pr_global_struct->trace_inopen = trace.inopen;
840 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
841 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
842 pr_global_struct->trace_plane_dist = trace.plane.dist;
844 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
846 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
854 Returns true if the given entity can move to the given position from it's
855 current position by walking or rolling.
857 scalar checkpos (entity, vector)
860 void PF_checkpos (void)
864 //============================================================================
867 qbyte checkpvs[MAX_MAP_LEAFS/8];
869 int PF_newcheckclient (int check)
875 // cycle to the next one
877 check = bound(1, check, svs.maxclients);
878 if (check == svs.maxclients)
886 pr_xfunction->builtinsprofile++;
888 if (i == svs.maxclients+1)
890 // look up the client's edict
892 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
893 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
895 // found a valid client (possibly the same one again)
899 // get the PVS for the entity
900 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
902 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
903 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
912 Returns a client (or object that has a client enemy) that would be a
915 If there is more than one valid option, they are cycled each frame
917 If (self.origin + self.viewofs) is not in the PVS of the current target,
918 it is not returned at all.
923 int c_invis, c_notvis;
924 void PF_checkclient (void)
929 // find a new check if on a new frame
930 if (sv.time - sv.lastchecktime >= 0.1)
932 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
933 sv.lastchecktime = sv.time;
936 // return check if it might be visible
937 ent = EDICT_NUM(sv.lastcheck);
938 if (ent->e->free || ent->v->health <= 0)
940 RETURN_EDICT(sv.edicts);
944 // if current entity can't possibly see the check entity, return 0
945 self = PROG_TO_EDICT(pr_global_struct->self);
946 VectorAdd(self->v->origin, self->v->view_ofs, view);
947 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
950 RETURN_EDICT(sv.edicts);
954 // might be able to see it
959 //============================================================================
966 Sends text over to the client's execution buffer
968 stuffcmd (clientent, value)
971 void PF_stuffcmd (void)
977 entnum = G_EDICTNUM(OFS_PARM0);
978 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
980 Con_Print("Can't stuffcmd to a non-client\n");
983 str = G_STRING(OFS_PARM1);
986 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
987 Host_ClientCommands ("%s", str);
995 Sends text to server console
1000 void PF_localcmd (void)
1002 Cbuf_AddText(G_STRING(OFS_PARM0));
1014 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1024 void PF_cvar_set (void)
1026 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1033 Returns a chain of entities that have origins within a spherical area
1035 findradius (origin, radius)
1038 void PF_findradius (void)
1040 edict_t *ent, *chain;
1041 vec_t radius, radius2;
1042 vec3_t org, eorg, mins, maxs;
1045 edict_t *touchedicts[MAX_EDICTS];
1047 chain = (edict_t *)sv.edicts;
1049 VectorCopy(G_VECTOR(OFS_PARM0), org);
1050 radius = G_FLOAT(OFS_PARM1);
1051 radius2 = radius * radius;
1053 mins[0] = org[0] - radius;
1054 mins[1] = org[1] - radius;
1055 mins[2] = org[2] - radius;
1056 maxs[0] = org[0] + radius;
1057 maxs[1] = org[1] + radius;
1058 maxs[2] = org[2] + radius;
1059 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1060 if (numtouchedicts > MAX_EDICTS)
1062 // this never happens
1063 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1064 numtouchedicts = MAX_EDICTS;
1066 for (i = 0;i < numtouchedicts;i++)
1068 ent = touchedicts[i];
1069 pr_xfunction->builtinsprofile++;
1070 // LordHavoc: compare against bounding box rather than center so it
1071 // doesn't miss large objects, and use DotProduct instead of Length
1072 // for a major speedup
1073 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1074 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1075 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1076 if (DotProduct(eorg, eorg) < radius2)
1078 ent->v->chain = EDICT_TO_PROG(chain);
1083 RETURN_EDICT(chain);
1092 void PF_dprint (void)
1094 char string[STRINGTEMP_LENGTH];
1095 if (developer.integer)
1097 PF_VarString(0, string, sizeof(string));
1106 v = G_FLOAT(OFS_PARM0);
1108 s = PR_GetTempString();
1109 if ((float)((int)v) == v)
1110 sprintf(s, "%i", (int)v);
1112 sprintf(s, "%f", v);
1113 G_INT(OFS_RETURN) = PR_SetString(s);
1119 v = G_FLOAT(OFS_PARM0);
1120 G_FLOAT(OFS_RETURN) = fabs(v);
1126 s = PR_GetTempString();
1127 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1128 G_INT(OFS_RETURN) = PR_SetString(s);
1134 s = PR_GetTempString();
1135 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1136 G_INT(OFS_RETURN) = PR_SetString(s);
1139 void PF_Spawn (void)
1142 pr_xfunction->builtinsprofile += 20;
1147 void PF_Remove (void)
1150 pr_xfunction->builtinsprofile += 20;
1152 ed = G_EDICT(OFS_PARM0);
1153 if (ed == sv.edicts)
1154 PF_WARNING("remove: tried to remove world\n");
1155 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1156 PF_WARNING("remove: tried to remove a client\n");
1157 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1158 if (ed->e->free && developer.integer)
1159 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1164 // entity (entity start, .string field, string match) find = #5;
1172 e = G_EDICTNUM(OFS_PARM0);
1173 f = G_INT(OFS_PARM1);
1174 s = G_STRING(OFS_PARM2);
1177 RETURN_EDICT(sv.edicts);
1181 for (e++ ; e < sv.num_edicts ; e++)
1183 pr_xfunction->builtinsprofile++;
1197 RETURN_EDICT(sv.edicts);
1200 // LordHavoc: added this for searching float, int, and entity reference fields
1201 void PF_FindFloat (void)
1208 e = G_EDICTNUM(OFS_PARM0);
1209 f = G_INT(OFS_PARM1);
1210 s = G_FLOAT(OFS_PARM2);
1212 for (e++ ; e < sv.num_edicts ; e++)
1214 pr_xfunction->builtinsprofile++;
1218 if (E_FLOAT(ed,f) == s)
1225 RETURN_EDICT(sv.edicts);
1228 // chained search for strings in entity fields
1229 // entity(.string field, string match) findchain = #402;
1230 void PF_findchain (void)
1235 edict_t *ent, *chain;
1237 chain = (edict_t *)sv.edicts;
1239 f = G_INT(OFS_PARM0);
1240 s = G_STRING(OFS_PARM1);
1243 RETURN_EDICT(sv.edicts);
1247 ent = NEXT_EDICT(sv.edicts);
1248 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1250 pr_xfunction->builtinsprofile++;
1253 t = E_STRING(ent,f);
1259 ent->v->chain = EDICT_TO_PROG(chain);
1263 RETURN_EDICT(chain);
1266 // LordHavoc: chained search for float, int, and entity reference fields
1267 // entity(.string field, float match) findchainfloat = #403;
1268 void PF_findchainfloat (void)
1273 edict_t *ent, *chain;
1275 chain = (edict_t *)sv.edicts;
1277 f = G_INT(OFS_PARM0);
1278 s = G_FLOAT(OFS_PARM1);
1280 ent = NEXT_EDICT(sv.edicts);
1281 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1283 pr_xfunction->builtinsprofile++;
1286 if (E_FLOAT(ent,f) != s)
1289 ent->v->chain = EDICT_TO_PROG(chain);
1293 RETURN_EDICT(chain);
1296 // LordHavoc: search for flags in float fields
1297 void PF_findflags (void)
1304 e = G_EDICTNUM(OFS_PARM0);
1305 f = G_INT(OFS_PARM1);
1306 s = (int)G_FLOAT(OFS_PARM2);
1308 for (e++ ; e < sv.num_edicts ; e++)
1310 pr_xfunction->builtinsprofile++;
1314 if ((int)E_FLOAT(ed,f) & s)
1321 RETURN_EDICT(sv.edicts);
1324 // LordHavoc: chained search for flags in float fields
1325 void PF_findchainflags (void)
1330 edict_t *ent, *chain;
1332 chain = (edict_t *)sv.edicts;
1334 f = G_INT(OFS_PARM0);
1335 s = (int)G_FLOAT(OFS_PARM1);
1337 ent = NEXT_EDICT(sv.edicts);
1338 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1340 pr_xfunction->builtinsprofile++;
1343 if (!((int)E_FLOAT(ent,f) & s))
1346 ent->v->chain = EDICT_TO_PROG(chain);
1350 RETURN_EDICT(chain);
1353 void PR_CheckEmptyString (char *s)
1356 PF_ERROR("Bad string");
1359 void PF_precache_file (void)
1360 { // precache_file is only used to copy files with qcc, it does nothing
1361 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1364 void PF_precache_sound (void)
1368 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
1370 if (sv.state != ss_loading)
1371 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1373 s = G_STRING(OFS_PARM0);
1374 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1375 PR_CheckEmptyString (s);
1377 for (i=0 ; i<limit ; i++)
1379 if (!sv.sound_precache[i])
1381 sv.sound_precache[i] = s;
1384 if (!strcmp(sv.sound_precache[i], s))
1387 PF_ERROR("PF_precache_sound: overflow");
1390 void PF_precache_model (void)
1394 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
1396 if (sv.state != ss_loading)
1397 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1399 s = G_STRING(OFS_PARM0);
1400 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1402 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1403 PR_CheckEmptyString (s);
1405 for (i = 0;i < limit;i++)
1407 if (!sv.model_precache[i])
1409 sv.model_precache[i] = s;
1410 sv.models[i] = Mod_ForName (s, true, false, false);
1413 if (!strcmp(sv.model_precache[i], s))
1416 PF_ERROR("PF_precache_model: overflow");
1420 void PF_coredump (void)
1425 void PF_traceon (void)
1430 void PF_traceoff (void)
1435 void PF_eprint (void)
1437 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1444 float(float yaw, float dist) walkmove
1447 void PF_walkmove (void)
1455 // assume failure if it returns early
1456 G_FLOAT(OFS_RETURN) = 0;
1458 ent = PROG_TO_EDICT(pr_global_struct->self);
1459 if (ent == sv.edicts)
1460 PF_WARNING("walkmove: can not modify world entity\n");
1462 PF_WARNING("walkmove: can not modify free entity\n");
1463 yaw = G_FLOAT(OFS_PARM0);
1464 dist = G_FLOAT(OFS_PARM1);
1466 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1469 yaw = yaw*M_PI*2 / 360;
1471 move[0] = cos(yaw)*dist;
1472 move[1] = sin(yaw)*dist;
1475 // save program state, because SV_movestep may call other progs
1476 oldf = pr_xfunction;
1477 oldself = pr_global_struct->self;
1479 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1482 // restore program state
1483 pr_xfunction = oldf;
1484 pr_global_struct->self = oldself;
1494 void PF_droptofloor (void)
1500 // assume failure if it returns early
1501 G_FLOAT(OFS_RETURN) = 0;
1503 ent = PROG_TO_EDICT(pr_global_struct->self);
1504 if (ent == sv.edicts)
1505 PF_WARNING("droptofloor: can not modify world entity\n");
1507 PF_WARNING("droptofloor: can not modify free entity\n");
1509 VectorCopy (ent->v->origin, end);
1512 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1514 if (trace.fraction != 1)
1516 VectorCopy (trace.endpos, ent->v->origin);
1517 SV_LinkEdict (ent, false);
1518 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1519 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1520 G_FLOAT(OFS_RETURN) = 1;
1521 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1522 ent->e->suspendedinairflag = true;
1530 void(float style, string value) lightstyle
1533 void PF_lightstyle (void)
1540 style = G_FLOAT(OFS_PARM0);
1541 val = G_STRING(OFS_PARM1);
1543 // change the string in sv
1544 sv.lightstyles[style] = val;
1546 // send message to all clients on this server
1547 if (sv.state != ss_active)
1550 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1552 if (client->netconnection)
1554 MSG_WriteChar (&client->message, svc_lightstyle);
1555 MSG_WriteChar (&client->message,style);
1556 MSG_WriteString (&client->message, val);
1564 f = G_FLOAT(OFS_PARM0);
1566 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1568 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1570 void PF_floor (void)
1572 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1576 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1585 void PF_checkbottom (void)
1587 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1595 void PF_pointcontents (void)
1597 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1604 entity nextent(entity)
1607 void PF_nextent (void)
1612 i = G_EDICTNUM(OFS_PARM0);
1615 pr_xfunction->builtinsprofile++;
1617 if (i == sv.num_edicts)
1619 RETURN_EDICT(sv.edicts);
1635 Pick a vector for the player to shoot along
1636 vector aim(entity, missilespeed)
1641 edict_t *ent, *check, *bestent;
1642 vec3_t start, dir, end, bestdir;
1645 float dist, bestdist;
1648 // assume failure if it returns early
1649 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1650 // if sv_aim is so high it can't possibly accept anything, skip out early
1651 if (sv_aim.value >= 1)
1654 ent = G_EDICT(OFS_PARM0);
1655 if (ent == sv.edicts)
1656 PF_WARNING("aim: can not use world entity\n");
1658 PF_WARNING("aim: can not use free entity\n");
1659 speed = G_FLOAT(OFS_PARM1);
1661 VectorCopy (ent->v->origin, start);
1664 // try sending a trace straight
1665 VectorCopy (pr_global_struct->v_forward, dir);
1666 VectorMA (start, 2048, dir, end);
1667 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1668 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1669 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1671 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1676 // try all possible entities
1677 VectorCopy (dir, bestdir);
1678 bestdist = sv_aim.value;
1681 check = NEXT_EDICT(sv.edicts);
1682 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1684 pr_xfunction->builtinsprofile++;
1685 if (check->v->takedamage != DAMAGE_AIM)
1689 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1690 continue; // don't aim at teammate
1691 for (j=0 ; j<3 ; j++)
1692 end[j] = check->v->origin[j]
1693 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1694 VectorSubtract (end, start, dir);
1695 VectorNormalize (dir);
1696 dist = DotProduct (dir, pr_global_struct->v_forward);
1697 if (dist < bestdist)
1698 continue; // to far to turn
1699 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1700 if (tr.ent == check)
1701 { // can shoot at this one
1709 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1710 dist = DotProduct (dir, pr_global_struct->v_forward);
1711 VectorScale (pr_global_struct->v_forward, dist, end);
1713 VectorNormalize (end);
1714 VectorCopy (end, G_VECTOR(OFS_RETURN));
1718 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1726 This was a major timewaster in progs, so it was converted to C
1729 void PF_changeyaw (void)
1732 float ideal, current, move, speed;
1734 ent = PROG_TO_EDICT(pr_global_struct->self);
1735 if (ent == sv.edicts)
1736 PF_WARNING("changeyaw: can not modify world entity\n");
1738 PF_WARNING("changeyaw: can not modify free entity\n");
1739 current = ANGLEMOD(ent->v->angles[1]);
1740 ideal = ent->v->ideal_yaw;
1741 speed = ent->v->yaw_speed;
1743 if (current == ideal)
1745 move = ideal - current;
1746 if (ideal > current)
1767 ent->v->angles[1] = ANGLEMOD (current + move);
1775 void PF_changepitch (void)
1778 float ideal, current, move, speed;
1781 ent = G_EDICT(OFS_PARM0);
1782 if (ent == sv.edicts)
1783 PF_WARNING("changepitch: can not modify world entity\n");
1785 PF_WARNING("changepitch: can not modify free entity\n");
1786 current = ANGLEMOD( ent->v->angles[0] );
1787 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1788 ideal = val->_float;
1791 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1794 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1795 speed = val->_float;
1798 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1802 if (current == ideal)
1804 move = ideal - current;
1805 if (ideal > current)
1826 ent->v->angles[0] = ANGLEMOD (current + move);
1830 ===============================================================================
1834 ===============================================================================
1837 #define MSG_BROADCAST 0 // unreliable to all
1838 #define MSG_ONE 1 // reliable to one (msg_entity)
1839 #define MSG_ALL 2 // reliable to all
1840 #define MSG_INIT 3 // write to the init string
1842 sizebuf_t *WriteDest (void)
1848 dest = G_FLOAT(OFS_PARM0);
1852 return &sv.datagram;
1855 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1856 entnum = NUM_FOR_EDICT(ent);
1857 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1858 Host_Error("WriteDest: tried to write to non-client\n");
1859 return &svs.clients[entnum-1].message;
1862 return &sv.reliable_datagram;
1868 Host_Error("WriteDest: bad destination");
1875 void PF_WriteByte (void)
1877 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1880 void PF_WriteChar (void)
1882 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1885 void PF_WriteShort (void)
1887 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1890 void PF_WriteLong (void)
1892 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1895 void PF_WriteAngle (void)
1897 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1900 void PF_WriteCoord (void)
1902 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1905 void PF_WriteString (void)
1907 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1911 void PF_WriteEntity (void)
1913 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1916 //=============================================================================
1918 void PF_makestatic (void)
1923 ent = G_EDICT(OFS_PARM0);
1924 if (ent == sv.edicts)
1925 PF_WARNING("makestatic: can not modify world entity\n");
1927 PF_WARNING("makestatic: can not modify free entity\n");
1930 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1935 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1936 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1937 MSG_WriteShort (&sv.signon, ent->v->frame);
1941 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1942 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1943 MSG_WriteByte (&sv.signon, ent->v->frame);
1946 MSG_WriteByte (&sv.signon, ent->v->colormap);
1947 MSG_WriteByte (&sv.signon, ent->v->skin);
1948 for (i=0 ; i<3 ; i++)
1950 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1951 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1954 // throw the entity away now
1958 //=============================================================================
1965 void PF_setspawnparms (void)
1971 ent = G_EDICT(OFS_PARM0);
1972 i = NUM_FOR_EDICT(ent);
1973 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1975 Con_Print("tried to setspawnparms on a non-client\n");
1979 // copy spawn parms out of the client_t
1980 client = svs.clients + i-1;
1981 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1982 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1990 void PF_changelevel (void)
1994 // make sure we don't issue two changelevels
1995 if (svs.changelevel_issued)
1997 svs.changelevel_issued = true;
1999 s = G_STRING(OFS_PARM0);
2000 Cbuf_AddText (va("changelevel %s\n",s));
2005 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
2010 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
2015 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
2022 Returns a vector of length < 1
2027 void PF_randomvec (void)
2032 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2033 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2034 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2036 while (DotProduct(temp, temp) >= 1);
2037 VectorCopy (temp, G_VECTOR(OFS_RETURN));
2044 Returns a color vector indicating the lighting at the requested point.
2046 (Internal Operation note: actually measures the light beneath the point, just like
2047 the model lighting on the client)
2052 void PF_GetLight (void)
2054 vec3_t ambientcolor, diffusecolor, diffusenormal;
2056 p = G_VECTOR(OFS_PARM0);
2057 VectorClear(ambientcolor);
2058 VectorClear(diffusecolor);
2059 VectorClear(diffusenormal);
2060 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2061 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2062 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2065 void PF_registercvar (void)
2068 name = G_STRING(OFS_PARM0);
2069 value = G_STRING(OFS_PARM1);
2070 G_FLOAT(OFS_RETURN) = 0;
2072 // first check to see if it has already been defined
2073 if (Cvar_FindVar (name))
2076 // check for overlap with a command
2077 if (Cmd_Exists (name))
2079 Con_Printf("PF_registercvar: %s is a command\n", name);
2083 Cvar_Get(name, value, 0);
2085 G_FLOAT(OFS_RETURN) = 1; // success
2092 returns the minimum of two supplied floats
2099 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2101 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2102 else if (pr_argc >= 3)
2105 float f = G_FLOAT(OFS_PARM0);
2106 for (i = 1;i < pr_argc;i++)
2107 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2108 f = G_FLOAT((OFS_PARM0+i*3));
2109 G_FLOAT(OFS_RETURN) = f;
2113 G_FLOAT(OFS_RETURN) = 0;
2114 PF_WARNING("min: must supply at least 2 floats\n");
2122 returns the maximum of two supplied floats
2129 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2131 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2132 else if (pr_argc >= 3)
2135 float f = G_FLOAT(OFS_PARM0);
2136 for (i = 1;i < pr_argc;i++)
2137 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2138 f = G_FLOAT((OFS_PARM0+i*3));
2139 G_FLOAT(OFS_RETURN) = f;
2143 G_FLOAT(OFS_RETURN) = 0;
2144 PF_WARNING("max: must supply at least 2 floats\n");
2152 returns number bounded by supplied range
2154 min(min, value, max)
2157 void PF_bound (void)
2159 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2166 returns a raised to power b
2173 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2180 copies data from one entity to another
2182 copyentity(src, dst)
2185 void PF_copyentity (void)
2188 in = G_EDICT(OFS_PARM0);
2189 if (in == sv.edicts)
2190 PF_WARNING("copyentity: can not read world entity\n");
2192 PF_WARNING("copyentity: can not read free entity\n");
2193 out = G_EDICT(OFS_PARM1);
2194 if (out == sv.edicts)
2195 PF_WARNING("copyentity: can not modify world entity\n");
2197 PF_WARNING("copyentity: can not modify free entity\n");
2198 memcpy(out->v, in->v, progs->entityfields * 4);
2205 sets the color of a client and broadcasts the update to all connected clients
2207 setcolor(clientent, value)
2210 void PF_setcolor (void)
2216 entnum = G_EDICTNUM(OFS_PARM0);
2217 i = G_FLOAT(OFS_PARM1);
2219 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2221 Con_Print("tried to setcolor a non-client\n");
2225 client = svs.clients + entnum-1;
2228 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2230 client->edict->v->team = (i & 15) + 1;
2233 if (client->old_colors != client->colors)
2235 client->old_colors = client->colors;
2236 // send notification to all clients
2237 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2238 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2239 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2247 effect(origin, modelname, startframe, framecount, framerate)
2250 void PF_effect (void)
2254 s = G_STRING(OFS_PARM1);
2256 PF_WARNING("effect: no model specified\n");
2258 i = SV_ModelIndex(s);
2260 PF_WARNING("effect: model not precached\n");
2261 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2264 void PF_te_blood (void)
2266 if (G_FLOAT(OFS_PARM2) < 1)
2268 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2269 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2271 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2272 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2273 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2275 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2276 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2277 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2279 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2282 void PF_te_bloodshower (void)
2284 if (G_FLOAT(OFS_PARM3) < 1)
2286 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2287 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2289 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2290 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2291 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2293 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2294 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2295 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2297 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2299 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2302 void PF_te_explosionrgb (void)
2304 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2305 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2307 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2309 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2311 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2312 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2313 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2316 void PF_te_particlecube (void)
2318 if (G_FLOAT(OFS_PARM3) < 1)
2320 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2321 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2324 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2325 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2335 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2337 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2338 // gravity true/false
2339 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2341 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2344 void PF_te_particlerain (void)
2346 if (G_FLOAT(OFS_PARM3) < 1)
2348 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2349 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2351 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2352 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2353 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2355 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2356 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2357 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2359 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2360 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2361 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2363 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2365 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2368 void PF_te_particlesnow (void)
2370 if (G_FLOAT(OFS_PARM3) < 1)
2372 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2373 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2375 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2376 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2377 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2381 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2383 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2384 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2385 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2387 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2389 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2392 void PF_te_spark (void)
2394 if (G_FLOAT(OFS_PARM2) < 1)
2396 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397 MSG_WriteByte(&sv.datagram, TE_SPARK);
2399 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2400 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2401 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2403 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2404 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2405 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2407 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2410 void PF_te_gunshotquad (void)
2412 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2413 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2415 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2416 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2417 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2420 void PF_te_spikequad (void)
2422 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2423 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2425 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2426 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2427 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2430 void PF_te_superspikequad (void)
2432 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2433 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2435 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2436 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2437 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2440 void PF_te_explosionquad (void)
2442 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2443 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2445 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2446 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2447 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2450 void PF_te_smallflash (void)
2452 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2453 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2455 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2456 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2457 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2460 void PF_te_customflash (void)
2462 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2464 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2465 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2467 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2468 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2469 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2471 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2473 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2475 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2476 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2477 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2480 void PF_te_gunshot (void)
2482 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2483 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2485 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2486 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2487 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2490 void PF_te_spike (void)
2492 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2493 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2495 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2496 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2497 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2500 void PF_te_superspike (void)
2502 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2503 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2505 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2506 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2507 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2510 void PF_te_explosion (void)
2512 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2513 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2515 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2516 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2517 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2520 void PF_te_tarexplosion (void)
2522 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2523 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2525 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2526 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2527 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2530 void PF_te_wizspike (void)
2532 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2533 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2535 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2536 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2537 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2540 void PF_te_knightspike (void)
2542 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2543 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2545 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2546 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2547 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2550 void PF_te_lavasplash (void)
2552 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2553 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2555 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2556 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2557 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2560 void PF_te_teleport (void)
2562 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2563 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2565 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2566 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2567 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2570 void PF_te_explosion2 (void)
2572 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2573 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2575 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2576 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2577 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2579 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2580 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2583 void PF_te_lightning1 (void)
2585 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2586 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2588 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2591 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2592 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2594 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2595 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2596 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2599 void PF_te_lightning2 (void)
2601 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2602 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2604 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2606 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2607 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2608 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2610 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2611 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2612 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2615 void PF_te_lightning3 (void)
2617 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2618 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2620 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2622 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2623 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2624 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2626 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2627 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2628 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2631 void PF_te_beam (void)
2633 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2634 MSG_WriteByte(&sv.datagram, TE_BEAM);
2636 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2638 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2639 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2640 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2642 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2643 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2644 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2647 void PF_te_plasmaburn (void)
2649 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2650 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2651 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2652 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2653 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2656 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2659 vec3_t v1, clipplanenormal, normal;
2660 vec_t clipplanedist, clipdist;
2662 if (surf->flags & SURF_PLANEBACK)
2663 VectorNegate(surf->plane->normal, normal);
2665 VectorCopy(surf->plane->normal, normal);
2666 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2668 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2669 VectorNormalizeFast(v1);
2670 CrossProduct(v1, normal, clipplanenormal);
2671 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2672 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2675 clipdist = -clipdist;
2676 VectorMA(out, clipdist, clipplanenormal, out);
2681 static msurface_t *getsurface(edict_t *ed, int surfnum)
2685 if (!ed || ed->e->free)
2687 modelindex = ed->v->modelindex;
2688 if (modelindex < 1 || modelindex >= MAX_MODELS)
2690 model = sv.models[modelindex];
2691 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2693 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2697 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2698 void PF_getsurfacenumpoints(void)
2701 // return 0 if no such surface
2702 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2704 G_FLOAT(OFS_RETURN) = 0;
2708 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2710 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2711 void PF_getsurfacepoint(void)
2716 VectorClear(G_VECTOR(OFS_RETURN));
2717 ed = G_EDICT(OFS_PARM0);
2718 if (!ed || ed->e->free)
2720 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2722 pointnum = G_FLOAT(OFS_PARM2);
2723 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2725 // FIXME: implement rotation/scaling
2726 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2728 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2729 void PF_getsurfacenormal(void)
2732 VectorClear(G_VECTOR(OFS_RETURN));
2733 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2735 // FIXME: implement rotation/scaling
2736 if (surf->flags & SURF_PLANEBACK)
2737 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2739 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2741 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2742 void PF_getsurfacetexture(void)
2745 G_INT(OFS_RETURN) = 0;
2746 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2748 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2750 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2751 void PF_getsurfacenearpoint(void)
2753 int surfnum, best, modelindex;
2755 vec_t dist, bestdist;
2760 G_FLOAT(OFS_RETURN) = -1;
2761 ed = G_EDICT(OFS_PARM0);
2762 point = G_VECTOR(OFS_PARM1);
2764 if (!ed || ed->e->free)
2766 modelindex = ed->v->modelindex;
2767 if (modelindex < 1 || modelindex >= MAX_MODELS)
2769 model = sv.models[modelindex];
2770 if (!model->brushq1.numsurfaces)
2773 // FIXME: implement rotation/scaling
2774 VectorSubtract(point, ed->v->origin, p);
2776 bestdist = 1000000000;
2777 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2779 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2780 dist = PlaneDiff(p, surf->plane);
2782 if (dist < bestdist)
2784 clippointtosurface(surf, p, clipped);
2785 VectorSubtract(clipped, p, clipped);
2786 dist += DotProduct(clipped, clipped);
2787 if (dist < bestdist)
2794 G_FLOAT(OFS_RETURN) = best;
2796 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2797 void PF_getsurfaceclippedpoint(void)
2802 VectorClear(G_VECTOR(OFS_RETURN));
2803 ed = G_EDICT(OFS_PARM0);
2804 if (!ed || ed->e->free)
2806 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2808 // FIXME: implement rotation/scaling
2809 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2810 clippointtosurface(surf, p, out);
2811 // FIXME: implement rotation/scaling
2812 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2815 #define MAX_PRFILES 256
2817 qfile_t *pr_files[MAX_PRFILES];
2819 void PR_Files_Init(void)
2821 memset(pr_files, 0, sizeof(pr_files));
2824 void PR_Files_CloseAll(void)
2827 for (i = 0;i < MAX_PRFILES;i++)
2830 FS_Close(pr_files[i]);
2835 //float(string s) stof = #81; // get numerical value from a string
2838 char string[STRINGTEMP_LENGTH];
2839 PF_VarString(0, string, sizeof(string));
2840 G_FLOAT(OFS_RETURN) = atof(string);
2843 //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
2846 int filenum, mode, i;
2847 char *modestring, *filename;
2848 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2849 if (pr_files[filenum] == NULL)
2851 if (filenum >= MAX_PRFILES)
2853 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2854 G_FLOAT(OFS_RETURN) = -2;
2857 mode = G_FLOAT(OFS_PARM1);
2860 case 0: // FILE_READ
2863 case 1: // FILE_APPEND
2866 case 2: // FILE_WRITE
2870 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2871 G_FLOAT(OFS_RETURN) = -3;
2874 filename = G_STRING(OFS_PARM0);
2875 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2876 // ../ is parent directory on many platforms
2877 // // is parent directory on Amiga
2878 // / at the beginning of a path is root on unix, and parent directory on Amiga
2879 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2880 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2881 for (i = 0;filename[i];i++)
2883 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2885 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);
2886 G_FLOAT(OFS_RETURN) = -4;
2890 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2892 if (pr_files[filenum] == NULL && modestring == "rb")
2893 pr_files[filenum] = FS_Open(filename, modestring, false);
2895 if (pr_files[filenum] == NULL)
2896 G_FLOAT(OFS_RETURN) = -1;
2898 G_FLOAT(OFS_RETURN) = filenum;
2901 //void(float fhandle) fclose = #111; // closes a file
2902 void PF_fclose(void)
2904 int filenum = G_FLOAT(OFS_PARM0);
2905 if (filenum < 0 || filenum >= MAX_PRFILES)
2907 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2910 if (pr_files[filenum] == NULL)
2912 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2915 FS_Close(pr_files[filenum]);
2916 pr_files[filenum] = NULL;
2919 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2923 static char string[STRINGTEMP_LENGTH];
2924 int filenum = G_FLOAT(OFS_PARM0);
2925 if (filenum < 0 || filenum >= MAX_PRFILES)
2927 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2930 if (pr_files[filenum] == NULL)
2932 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2938 c = FS_Getc(pr_files[filenum]);
2939 if (c == '\r' || c == '\n' || c < 0)
2941 if (end < STRINGTEMP_LENGTH - 1)
2945 // remove \n following \r
2947 c = FS_Getc(pr_files[filenum]);
2948 if (developer.integer)
2949 Con_Printf("fgets: %s\n", string);
2951 G_INT(OFS_RETURN) = PR_SetString(string);
2953 G_INT(OFS_RETURN) = 0;
2956 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2960 char string[STRINGTEMP_LENGTH];
2961 int filenum = G_FLOAT(OFS_PARM0);
2962 if (filenum < 0 || filenum >= MAX_PRFILES)
2964 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2967 if (pr_files[filenum] == NULL)
2969 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2972 PF_VarString(1, string, sizeof(string));
2973 if ((stringlength = strlen(string)))
2974 FS_Write(pr_files[filenum], string, stringlength);
2975 if (developer.integer)
2976 Con_Printf("fputs: %s\n", string);
2979 //float(string s) strlen = #114; // returns how many characters are in a string
2980 void PF_strlen(void)
2983 s = G_STRING(OFS_PARM0);
2985 G_FLOAT(OFS_RETURN) = strlen(s);
2987 G_FLOAT(OFS_RETURN) = 0;
2990 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2991 void PF_strcat(void)
2993 char *s = PR_GetTempString();
2994 PF_VarString(0, s, STRINGTEMP_LENGTH);
2995 G_INT(OFS_RETURN) = PR_SetString(s);
2998 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2999 void PF_substring(void)
3001 int i, start, length;
3002 char *s, *string = PR_GetTempString();
3003 s = G_STRING(OFS_PARM0);
3004 start = G_FLOAT(OFS_PARM1);
3005 length = G_FLOAT(OFS_PARM2);
3008 for (i = 0;i < start && *s;i++, s++);
3009 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3012 G_INT(OFS_RETURN) = PR_SetString(string);
3015 //vector(string s) stov = #117; // returns vector value from a string
3018 char string[STRINGTEMP_LENGTH];
3019 PF_VarString(0, string, sizeof(string));
3020 Math_atov(string, G_VECTOR(OFS_RETURN));
3023 //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)
3024 void PF_strzone(void)
3027 in = G_STRING(OFS_PARM0);
3028 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3030 G_INT(OFS_RETURN) = PR_SetString(out);
3033 //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!!!)
3034 void PF_strunzone(void)
3036 Mem_Free(G_STRING(OFS_PARM0));
3039 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3040 //this function originally written by KrimZon, made shorter by LordHavoc
3041 void PF_clientcommand (void)
3043 client_t *temp_client;
3046 //find client for this entity
3047 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3048 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3050 Con_Print("PF_clientcommand: entity is not a client\n");
3054 temp_client = host_client;
3055 host_client = svs.clients + i;
3056 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3057 host_client = temp_client;
3060 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3061 //this function originally written by KrimZon, made shorter by LordHavoc
3062 //20040203: rewritten by LordHavoc (no longer uses allocations)
3064 char *tokens[256], tokenbuf[4096];
3065 void PF_tokenize (void)
3069 p = G_STRING(OFS_PARM0);
3073 while(COM_ParseToken(&p, false))
3075 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3077 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3079 tokens[num_tokens++] = tokenbuf + pos;
3080 strcpy(tokenbuf + pos, com_token);
3081 pos += strlen(com_token) + 1;
3084 G_FLOAT(OFS_RETURN) = num_tokens;
3087 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3088 //this function originally written by KrimZon, made shorter by LordHavoc
3091 int token_num = G_FLOAT(OFS_PARM0);
3092 if (token_num >= 0 && token_num < num_tokens)
3093 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3095 G_INT(OFS_RETURN) = PR_SetString("");
3098 //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)
3099 void PF_setattachment (void)
3101 edict_t *e = G_EDICT(OFS_PARM0);
3102 edict_t *tagentity = G_EDICT(OFS_PARM1);
3103 char *tagname = G_STRING(OFS_PARM2);
3109 PF_WARNING("setattachment: can not modify world entity\n");
3111 PF_WARNING("setattachment: can not modify free entity\n");
3113 if (tagentity == NULL)
3114 tagentity = sv.edicts;
3116 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3118 v->edict = EDICT_TO_PROG(tagentity);
3120 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3123 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3125 modelindex = (int)tagentity->v->modelindex;
3126 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3128 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3129 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3130 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3132 // FIXME: use a model function to get tag info (need to handle skeletal)
3133 if (v->_float == 0 && model->alias.aliasnum_tags)
3134 for (i = 0;i < model->alias.aliasnum_tags;i++)
3135 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3138 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);
3141 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));
3145 /////////////////////////////////////////
3146 // DP_MD3_TAGINFO extension coded by VorteX
3148 //float(entity ent, string tagname) gettagindex;
3149 void PF_gettagindex (void)
3151 edict_t *e = G_EDICT(OFS_PARM0);
3152 const char *tagname = G_STRING(OFS_PARM1);
3153 int modelindex, tagindex, i;
3157 PF_WARNING("gettagindex: can't affect world entity\n");
3159 PF_WARNING("gettagindex: can't affect free entity\n");
3161 modelindex = (int)e->v->modelindex;
3162 if (modelindex <= 0 || modelindex > MAX_MODELS)
3164 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3167 model = sv.models[modelindex];
3170 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3172 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3174 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3183 for (i = 0;i < model->alias.aliasnum_tags; i++)
3185 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3193 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(e), tagname);
3194 G_FLOAT(OFS_RETURN) = tagindex + 1;
3197 // Warnings/errors code:
3198 // 0 - normal (everything all-right)
3201 // 3 - null or non-precached model
3202 // 4 - no tags with requested index
3203 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3207 int modelindex, tagsnum, reqframe;
3208 matrix4x4_t entitymatrix, tagmatrix;
3211 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3213 if (ent == sv.edicts)
3218 modelindex = (int)ent->v->modelindex;
3219 if (modelindex <= 0 || modelindex > MAX_MODELS)
3222 model = sv.models[modelindex];
3223 tagsnum = model->alias.aliasnum_tags;
3225 if (tagindex <= 0 || tagindex > tagsnum)
3227 if (tagsnum && tagindex) // Only appear if model has no tags or not-null tag requested
3232 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3233 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3235 reqframe = ent->v->frame;
3237 // just reusing a temp
3238 modelindex = (tagindex - 1) + ent->v->frame*tagsnum;
3240 // transform tag by its own entity matrix
3241 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[modelindex].matrix);
3242 // FIXME: add scale parameter
3244 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3245 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);
3246 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3247 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3248 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];
3249 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];
3250 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];
3252 // additional actions for render-view entities
3253 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3254 {// RENDER_VIEWMODEL
3255 Matrix4x4_Copy(&tagmatrix, out);
3256 ent = EDICT_NUM(val->edict);
3257 // FIXME: add bobbing (cl_bob), add scale parameter
3259 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);
3260 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3261 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];
3262 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];
3263 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];
3264 Con_DPrintf("SV_GetTagMatrix: returned origin is %f %f %f\n", out->m[0][3], out->m[1][3], out->m[2][3]);
3267 // RENDER_VIEWMODEL can't be attached by tag, right?
3268 val = GETEDICTFIELDVALUE(ent, eval_tag_entity);
3270 {// DP_GFX_QUAKE3MODELTAGS
3273 ent = EDICT_NUM(val->edict);
3274 // FIXME: add scale parameter
3275 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);
3276 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3277 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3278 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];
3279 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];
3280 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];
3283 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3288 //vector(entity ent, float tagindex) gettaginfo;
3289 void PF_gettaginfo (void)
3291 edict_t *e = G_EDICT(OFS_PARM0);
3292 int tagindex = (int)G_FLOAT(OFS_PARM1);
3293 matrix4x4_t tag_matrix;
3296 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3297 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3302 PF_WARNING("gettagindex: can't affect world entity\n");
3305 PF_WARNING("gettagindex: can't affect free entity\n");
3308 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3311 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3317 /////////////////////////////////////////
3318 // DP_QC_FS_SEARCH extension
3320 // qc fs search handling
3321 #define MAX_SEARCHES 128
3323 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3325 void PR_Search_Init(void)
3327 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3330 void PR_Search_Reset(void)
3333 // reset the fssearch list
3334 for(i = 0; i < MAX_SEARCHES; i++)
3335 if(pr_fssearchlist[i])
3336 FS_FreeSearch(pr_fssearchlist[i]);
3337 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3344 float search_begin(string pattern, float caseinsensitive, float quiet)
3347 void PF_search_begin(void)
3351 int caseinsens, quiet;
3353 pattern = G_STRING(OFS_PARM0);
3355 PR_CheckEmptyString(pattern);
3357 caseinsens = G_FLOAT(OFS_PARM1);
3358 quiet = G_FLOAT(OFS_PARM2);
3360 for(handle = 0; handle < MAX_SEARCHES; handle++)
3361 if(!pr_fssearchlist[handle])
3364 if(handle >= MAX_SEARCHES)
3366 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3367 G_FLOAT(OFS_RETURN) = -2;
3371 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3372 G_FLOAT(OFS_RETURN) = -1;
3374 G_FLOAT(OFS_RETURN) = handle;
3381 void search_end(float handle)
3384 void PF_search_end(void)
3388 handle = G_FLOAT(OFS_PARM0);
3390 if(handle < 0 || handle >= MAX_SEARCHES)
3392 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3395 if(pr_fssearchlist[handle] == NULL)
3397 Con_Printf("PF_search_end: no such handle %i\n", handle);
3401 FS_FreeSearch(pr_fssearchlist[handle]);
3402 pr_fssearchlist[handle] = NULL;
3409 float search_getsize(float handle)
3412 void PF_search_getsize(void)
3416 handle = G_FLOAT(OFS_PARM0);
3418 if(handle < 0 || handle >= MAX_SEARCHES)
3420 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3423 if(pr_fssearchlist[handle] == NULL)
3425 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3429 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3434 VM_search_getfilename
3436 string search_getfilename(float handle, float num)
3439 void PF_search_getfilename(void)
3441 int handle, filenum;
3444 handle = G_FLOAT(OFS_PARM0);
3445 filenum = G_FLOAT(OFS_PARM1);
3447 if(handle < 0 || handle >= MAX_SEARCHES)
3449 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3452 if(pr_fssearchlist[handle] == NULL)
3454 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3457 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3459 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3463 tmp = PR_GetTempString();
3464 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3466 G_INT(OFS_RETURN) = PR_SetString(tmp);
3469 void PF_cvar_string (void)
3475 str = G_STRING(OFS_PARM0);
3476 var = Cvar_FindVar (str);
3479 tmp = PR_GetTempString();
3480 strcpy(tmp, var->string);
3484 G_INT(OFS_RETURN) = PR_SetString(tmp);
3487 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3488 void PF_dropclient (void)
3491 client_t *oldhostclient;
3492 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3493 if (clientnum < 0 || clientnum >= svs.maxclients)
3494 PF_WARNING("dropclient: not a client\n");
3495 if (!svs.clients[clientnum].active)
3496 PF_WARNING("dropclient: that client slot is not connected\n");
3497 oldhostclient = host_client;
3498 host_client = svs.clients + clientnum;
3499 SV_DropClient(false);
3500 host_client = oldhostclient;
3504 builtin_t pr_builtin[] =
3507 PF_makevectors, // #1 void(entity e) makevectors
3508 PF_setorigin, // #2 void(entity e, vector o) setorigin
3509 PF_setmodel, // #3 void(entity e, string m) setmodel
3510 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3511 NULL, // #5 void(entity e, vector min, vector max) setabssize
3512 PF_break, // #6 void() break
3513 PF_random, // #7 float() random
3514 PF_sound, // #8 void(entity e, float chan, string samp) sound
3515 PF_normalize, // #9 vector(vector v) normalize
3516 PF_error, // #10 void(string e) error
3517 PF_objerror, // #11 void(string e) objerror
3518 PF_vlen, // #12 float(vector v) vlen
3519 PF_vectoyaw, // #13 float(vector v) vectoyaw
3520 PF_Spawn, // #14 entity() spawn
3521 PF_Remove, // #15 void(entity e) remove
3522 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3523 PF_checkclient, // #17 entity() clientlist
3524 PF_Find, // #18 entity(entity start, .string fld, string match) find
3525 PF_precache_sound, // #19 void(string s) precache_sound
3526 PF_precache_model, // #20 void(string s) precache_model
3527 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3528 PF_findradius, // #22 entity(vector org, float rad) findradius
3529 PF_bprint, // #23 void(string s) bprint
3530 PF_sprint, // #24 void(entity client, string s) sprint
3531 PF_dprint, // #25 void(string s) dprint
3532 PF_ftos, // #26 void(string s) ftos
3533 PF_vtos, // #27 void(string s) vtos
3534 PF_coredump, // #28 void() coredump
3535 PF_traceon, // #29 void() traceon
3536 PF_traceoff, // #30 void() traceoff
3537 PF_eprint, // #31 void(entity e) eprint
3538 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3540 PF_droptofloor, // #34 float() droptofloor
3541 PF_lightstyle, // #35 void(float style, string value) lightstyle
3542 PF_rint, // #36 float(float v) rint
3543 PF_floor, // #37 float(float v) floor
3544 PF_ceil, // #38 float(float v) ceil
3546 PF_checkbottom, // #40 float(entity e) checkbottom
3547 PF_pointcontents , // #41 float(vector v) pointcontents
3549 PF_fabs, // #43 float(float f) fabs
3550 PF_aim, // #44 vector(entity e, float speed) aim
3551 PF_cvar, // #45 float(string s) cvar
3552 PF_localcmd, // #46 void(string s) localcmd
3553 PF_nextent, // #47 entity(entity e) nextent
3554 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3555 PF_changeyaw, // #49 void() ChangeYaw
3557 PF_vectoangles, // #51 vector(vector v) vectoangles
3558 PF_WriteByte, // #52 void(float to, float f) WriteByte
3559 PF_WriteChar, // #53 void(float to, float f) WriteChar
3560 PF_WriteShort, // #54 void(float to, float f) WriteShort
3561 PF_WriteLong, // #55 void(float to, float f) WriteLong
3562 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3563 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3564 PF_WriteString, // #58 void(float to, string s) WriteString
3565 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3566 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3567 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3568 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3569 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3570 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3571 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3573 SV_MoveToGoal, // #67 void(float step) movetogoal
3574 PF_precache_file, // #68 string(string s) precache_file
3575 PF_makestatic, // #69 void(entity e) makestatic
3576 PF_changelevel, // #70 void(string s) changelevel
3578 PF_cvar_set, // #72 void(string var, string val) cvar_set
3579 PF_centerprint, // #73 void(entity client, strings) centerprint
3580 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3581 PF_precache_model, // #75 string(string s) precache_model2
3582 PF_precache_sound, // #76 string(string s) precache_sound2
3583 PF_precache_file, // #77 string(string s) precache_file2
3584 PF_setspawnparms, // #78 void(entity e) setspawnparms
3587 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3596 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3597 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3598 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3599 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3600 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3601 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3602 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3603 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3604 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3605 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3616 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3617 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3618 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3619 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3620 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3621 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3622 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3623 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3624 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3625 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3626 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3627 a a a a a a a a // #120-199
3628 a a a a a a a a a a // #200-299
3629 a a a a a a a a a a // #300-399
3630 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3631 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3632 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3633 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3634 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3635 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3636 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3637 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3638 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3639 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3640 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3641 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3642 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3643 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3644 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3645 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3646 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3647 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3648 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3649 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3650 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3651 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3652 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3653 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3654 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3655 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3656 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3657 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3658 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3659 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3660 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3661 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3662 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3663 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3664 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3665 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3666 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3667 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3668 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3669 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3670 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3671 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3672 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3673 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3674 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3675 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3676 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3677 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3678 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3679 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3680 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3681 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3682 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3683 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3690 a a a a // #460-499 (LordHavoc)
3693 builtin_t *pr_builtins = pr_builtin;
3694 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3696 void PR_Cmd_Init(void)
3698 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3703 void PR_Cmd_Reset(void)
3705 Mem_EmptyPool(pr_strings_mempool);
3707 PR_Files_CloseAll();