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 "
137 "DP_SV_CLIENTCOLORS "
139 "DP_SV_DRAWONLYTOCLIENT "
142 "DP_SV_NODRAWTOCLIENT "
144 "DP_SV_PLAYERPHYSICS "
146 "DP_SV_ROTATINGBMODEL "
152 "DP_TE_EXPLOSIONRGB "
154 "DP_TE_PARTICLECUBE "
155 "DP_TE_PARTICLERAIN "
156 "DP_TE_PARTICLESNOW "
158 "DP_TE_QUADEFFECTS1 "
161 "DP_TE_STANDARDEFFECTBUILTINS "
164 "KRIMZON_SV_PARSECLIENTCOMMAND "
168 "TENEBRAE_GFX_DLIGHTS "
172 qboolean checkextension(char *name)
177 for (e = ENGINE_EXTENSIONS;*e;e++)
184 while (*e && *e != ' ')
186 if (e - start == len)
187 if (!strncasecmp(start, name, len))
197 returns true if the extension is supported by the server
199 checkextension(extensionname)
202 void PF_checkextension (void)
204 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
211 This is a TERMINAL error, which will kill off the entire server.
220 char string[STRINGTEMP_LENGTH];
222 PF_VarString(0, string, sizeof(string));
223 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
224 ed = PROG_TO_EDICT(pr_global_struct->self);
227 PF_ERROR("Program error");
234 Dumps out self, then an error message. The program is aborted and self is
235 removed, but the level can continue.
240 void PF_objerror (void)
243 char string[STRINGTEMP_LENGTH];
245 PF_VarString(0, string, sizeof(string));
246 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
247 ed = PROG_TO_EDICT(pr_global_struct->self);
257 Writes new values for v_forward, v_up, and v_right based on angles
261 void PF_makevectors (void)
263 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
270 Writes new values for v_forward, v_up, and v_right based on the given forward vector
271 vectorvectors(vector, vector)
274 void PF_vectorvectors (void)
276 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
277 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
284 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.
286 setorigin (entity, origin)
289 void PF_setorigin (void)
294 e = G_EDICT(OFS_PARM0);
296 PF_WARNING("setorigin: can not modify world entity\n");
298 PF_WARNING("setorigin: can not modify free entity\n");
299 org = G_VECTOR(OFS_PARM1);
300 VectorCopy (org, e->v->origin);
301 SV_LinkEdict (e, false);
305 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
309 for (i=0 ; i<3 ; i++)
311 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
313 // set derived values
314 VectorCopy (min, e->v->mins);
315 VectorCopy (max, e->v->maxs);
316 VectorSubtract (max, min, e->v->size);
318 SV_LinkEdict (e, false);
325 the size box is rotated by the current angle
326 LordHavoc: no it isn't...
328 setsize (entity, minvector, maxvector)
331 void PF_setsize (void)
336 e = G_EDICT(OFS_PARM0);
338 PF_WARNING("setsize: can not modify world entity\n");
340 PF_WARNING("setsize: can not modify free entity\n");
341 min = G_VECTOR(OFS_PARM1);
342 max = G_VECTOR(OFS_PARM2);
343 SetMinMaxSize (e, min, max, false);
351 setmodel(entity, model)
354 void PF_setmodel (void)
361 e = G_EDICT(OFS_PARM0);
363 PF_WARNING("setmodel: can not modify world entity\n");
365 PF_WARNING("setmodel: can not modify free entity\n");
366 m = G_STRING(OFS_PARM1);
368 // check to see if model was properly precached
369 for (i=0, check = sv.model_precache ; *check ; i++, check++)
370 if (!strcmp(*check, m))
374 PF_WARNING(va("setmodel: no precache for model \"%s\"\n", m));
377 e->v->model = PR_SetString(*check);
378 e->v->modelindex = i;
380 mod = sv.models[ (int)e->v->modelindex];
383 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
385 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
392 broadcast print to everyone on server
397 void PF_bprint (void)
399 char string[STRINGTEMP_LENGTH];
400 PF_VarString(0, string, sizeof(string));
401 SV_BroadcastPrint(string);
408 single print to a specific client
410 sprint(clientent, value)
413 void PF_sprint (void)
417 char string[STRINGTEMP_LENGTH];
419 entnum = G_EDICTNUM(OFS_PARM0);
421 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
423 Con_Print("tried to sprint to a non-client\n");
427 client = svs.clients + entnum-1;
428 PF_VarString(1, string, sizeof(string));
429 MSG_WriteChar(&client->message,svc_print);
430 MSG_WriteString(&client->message, string);
438 single print to a specific client
440 centerprint(clientent, value)
443 void PF_centerprint (void)
447 char string[STRINGTEMP_LENGTH];
449 entnum = G_EDICTNUM(OFS_PARM0);
451 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
453 Con_Print("tried to sprint to a non-client\n");
457 client = svs.clients + entnum-1;
458 PF_VarString(1, string, sizeof(string));
459 MSG_WriteChar(&client->message,svc_centerprint);
460 MSG_WriteString(&client->message, string);
468 vector normalize(vector)
471 void PF_normalize (void)
477 value1 = G_VECTOR(OFS_PARM0);
479 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
483 newvalue[0] = newvalue[1] = newvalue[2] = 0;
487 newvalue[0] = value1[0] * new;
488 newvalue[1] = value1[1] * new;
489 newvalue[2] = value1[2] * new;
492 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
507 value1 = G_VECTOR(OFS_PARM0);
509 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
512 G_FLOAT(OFS_RETURN) = new;
519 float vectoyaw(vector)
522 void PF_vectoyaw (void)
527 value1 = G_VECTOR(OFS_PARM0);
529 if (value1[1] == 0 && value1[0] == 0)
533 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
538 G_FLOAT(OFS_RETURN) = yaw;
546 vector vectoangles(vector)
549 void PF_vectoangles (void)
551 double value1[3], forward, yaw, pitch;
553 VectorCopy(G_VECTOR(OFS_PARM0), value1);
555 if (value1[1] == 0 && value1[0] == 0)
565 // LordHavoc: optimized a bit
568 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
572 else if (value1[1] > 0)
577 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
578 pitch = (atan2(value1[2], forward) * 180 / M_PI);
583 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
590 Returns a number from 0<= num < 1
595 void PF_random (void)
599 num = (rand ()&0x7fff) / ((float)0x7fff);
601 G_FLOAT(OFS_RETURN) = num;
608 particle(origin, color, count)
611 void PF_particle (void)
617 org = G_VECTOR(OFS_PARM0);
618 dir = G_VECTOR(OFS_PARM1);
619 color = G_FLOAT(OFS_PARM2);
620 count = G_FLOAT(OFS_PARM3);
621 SV_StartParticle (org, dir, color, count);
631 void PF_ambientsound (void)
636 float vol, attenuation;
639 pos = G_VECTOR (OFS_PARM0);
640 samp = G_STRING(OFS_PARM1);
641 vol = G_FLOAT(OFS_PARM2);
642 attenuation = G_FLOAT(OFS_PARM3);
644 // check to see if samp was properly precached
645 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
646 if (!strcmp(*check,samp))
651 Con_Printf("no precache: %s\n", samp);
659 // add an svc_spawnambient command to the level signon packet
662 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
664 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
666 MSG_WriteVector(&sv.signon, pos, sv.protocol);
669 MSG_WriteShort (&sv.signon, soundnum);
671 MSG_WriteByte (&sv.signon, soundnum);
673 MSG_WriteByte (&sv.signon, vol*255);
674 MSG_WriteByte (&sv.signon, attenuation*64);
682 Each entity can have eight independant sound sources, like voice,
685 Channel 0 is an auto-allocate channel, the others override anything
686 already running on that entity/channel pair.
688 An attenuation of 0 will play full volume everywhere in the level.
689 Larger attenuations will drop off.
701 entity = G_EDICT(OFS_PARM0);
702 channel = G_FLOAT(OFS_PARM1);
703 sample = G_STRING(OFS_PARM2);
704 volume = G_FLOAT(OFS_PARM3) * 255;
705 attenuation = G_FLOAT(OFS_PARM4);
707 if (volume < 0 || volume > 255)
708 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
710 if (attenuation < 0 || attenuation > 4)
711 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
713 if (channel < 0 || channel > 7)
714 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
716 SV_StartSound (entity, channel, sample, volume, attenuation);
728 PF_ERROR("break: break statement\n");
735 Used for use tracing and shot targeting
736 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
737 if the tryents flag is set.
739 traceline (vector1, vector2, tryents)
742 void PF_traceline (void)
749 pr_xfunction->builtinsprofile += 30;
751 v1 = G_VECTOR(OFS_PARM0);
752 v2 = G_VECTOR(OFS_PARM1);
753 move = G_FLOAT(OFS_PARM2);
754 ent = G_EDICT(OFS_PARM3);
756 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
758 pr_global_struct->trace_allsolid = trace.allsolid;
759 pr_global_struct->trace_startsolid = trace.startsolid;
760 pr_global_struct->trace_fraction = trace.fraction;
761 pr_global_struct->trace_inwater = trace.inwater;
762 pr_global_struct->trace_inopen = trace.inopen;
763 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
764 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
765 pr_global_struct->trace_plane_dist = trace.plane.dist;
767 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
769 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
770 // FIXME: add trace_endcontents
778 Used for use tracing and shot targeting
779 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
780 if the tryents flag is set.
782 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
785 // LordHavoc: added this for my own use, VERY useful, similar to traceline
786 void PF_tracebox (void)
788 float *v1, *v2, *m1, *m2;
793 pr_xfunction->builtinsprofile += 30;
795 v1 = G_VECTOR(OFS_PARM0);
796 m1 = G_VECTOR(OFS_PARM1);
797 m2 = G_VECTOR(OFS_PARM2);
798 v2 = G_VECTOR(OFS_PARM3);
799 move = G_FLOAT(OFS_PARM4);
800 ent = G_EDICT(OFS_PARM5);
802 trace = SV_Move (v1, m1, m2, v2, move, ent);
804 pr_global_struct->trace_allsolid = trace.allsolid;
805 pr_global_struct->trace_startsolid = trace.startsolid;
806 pr_global_struct->trace_fraction = trace.fraction;
807 pr_global_struct->trace_inwater = trace.inwater;
808 pr_global_struct->trace_inopen = trace.inopen;
809 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
810 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
811 pr_global_struct->trace_plane_dist = trace.plane.dist;
813 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
815 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
818 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
819 void PF_TraceToss (void)
825 pr_xfunction->builtinsprofile += 600;
827 ent = G_EDICT(OFS_PARM0);
828 if (ent == sv.edicts)
829 PF_WARNING("tracetoss: can not use world entity\n");
830 ignore = G_EDICT(OFS_PARM1);
832 trace = SV_Trace_Toss (ent, ignore);
834 pr_global_struct->trace_allsolid = trace.allsolid;
835 pr_global_struct->trace_startsolid = trace.startsolid;
836 pr_global_struct->trace_fraction = trace.fraction;
837 pr_global_struct->trace_inwater = trace.inwater;
838 pr_global_struct->trace_inopen = trace.inopen;
839 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
840 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
841 pr_global_struct->trace_plane_dist = trace.plane.dist;
843 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
845 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
853 Returns true if the given entity can move to the given position from it's
854 current position by walking or rolling.
856 scalar checkpos (entity, vector)
859 void PF_checkpos (void)
863 //============================================================================
866 qbyte checkpvs[MAX_MAP_LEAFS/8];
868 int PF_newcheckclient (int check)
874 // cycle to the next one
876 check = bound(1, check, svs.maxclients);
877 if (check == svs.maxclients)
885 pr_xfunction->builtinsprofile++;
887 if (i == svs.maxclients+1)
889 // look up the client's edict
891 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
892 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
894 // found a valid client (possibly the same one again)
898 // get the PVS for the entity
899 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
901 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
902 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
911 Returns a client (or object that has a client enemy) that would be a
914 If there is more than one valid option, they are cycled each frame
916 If (self.origin + self.viewofs) is not in the PVS of the current target,
917 it is not returned at all.
922 int c_invis, c_notvis;
923 void PF_checkclient (void)
928 // find a new check if on a new frame
929 if (sv.time - sv.lastchecktime >= 0.1)
931 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
932 sv.lastchecktime = sv.time;
935 // return check if it might be visible
936 ent = EDICT_NUM(sv.lastcheck);
937 if (ent->e->free || ent->v->health <= 0)
939 RETURN_EDICT(sv.edicts);
943 // if current entity can't possibly see the check entity, return 0
944 self = PROG_TO_EDICT(pr_global_struct->self);
945 VectorAdd(self->v->origin, self->v->view_ofs, view);
946 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
949 RETURN_EDICT(sv.edicts);
953 // might be able to see it
958 //============================================================================
965 Sends text over to the client's execution buffer
967 stuffcmd (clientent, value)
970 void PF_stuffcmd (void)
976 entnum = G_EDICTNUM(OFS_PARM0);
977 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
979 Con_Print("Can't stuffcmd to a non-client\n");
982 str = G_STRING(OFS_PARM1);
985 host_client = svs.clients + entnum-1;
986 Host_ClientCommands ("%s", str);
994 Sends text to server console
999 void PF_localcmd (void)
1001 Cbuf_AddText(G_STRING(OFS_PARM0));
1013 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1023 void PF_cvar_set (void)
1025 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1032 Returns a chain of entities that have origins within a spherical area
1034 findradius (origin, radius)
1037 void PF_findradius (void)
1039 edict_t *ent, *chain;
1040 vec_t radius, radius2;
1041 vec3_t org, eorg, mins, maxs;
1044 edict_t *touchedicts[MAX_EDICTS];
1046 chain = (edict_t *)sv.edicts;
1048 VectorCopy(G_VECTOR(OFS_PARM0), org);
1049 radius = G_FLOAT(OFS_PARM1);
1050 radius2 = radius * radius;
1052 mins[0] = org[0] - radius;
1053 mins[1] = org[1] - radius;
1054 mins[2] = org[2] - radius;
1055 maxs[0] = org[0] + radius;
1056 maxs[1] = org[1] + radius;
1057 maxs[2] = org[2] + radius;
1058 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1059 if (numtouchedicts > MAX_EDICTS)
1061 // this never happens
1062 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1063 numtouchedicts = MAX_EDICTS;
1065 for (i = 0;i < numtouchedicts;i++)
1067 ent = touchedicts[i];
1068 pr_xfunction->builtinsprofile++;
1069 // LordHavoc: compare against bounding box rather than center so it
1070 // doesn't miss large objects, and use DotProduct instead of Length
1071 // for a major speedup
1072 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1073 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1074 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1075 if (DotProduct(eorg, eorg) < radius2)
1077 ent->v->chain = EDICT_TO_PROG(chain);
1082 RETURN_EDICT(chain);
1091 void PF_dprint (void)
1093 char string[STRINGTEMP_LENGTH];
1094 if (developer.integer)
1096 PF_VarString(0, string, sizeof(string));
1105 v = G_FLOAT(OFS_PARM0);
1107 s = PR_GetTempString();
1108 if ((float)((int)v) == v)
1109 sprintf(s, "%i", (int)v);
1111 sprintf(s, "%f", v);
1112 G_INT(OFS_RETURN) = PR_SetString(s);
1118 v = G_FLOAT(OFS_PARM0);
1119 G_FLOAT(OFS_RETURN) = fabs(v);
1125 s = PR_GetTempString();
1126 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1127 G_INT(OFS_RETURN) = PR_SetString(s);
1133 s = PR_GetTempString();
1134 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1135 G_INT(OFS_RETURN) = PR_SetString(s);
1138 void PF_Spawn (void)
1141 pr_xfunction->builtinsprofile += 20;
1146 void PF_Remove (void)
1149 pr_xfunction->builtinsprofile += 20;
1151 ed = G_EDICT(OFS_PARM0);
1152 if (ed == sv.edicts)
1153 PF_WARNING("remove: tried to remove world\n");
1154 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1155 PF_WARNING("remove: tried to remove a client\n");
1156 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1157 if (ed->e->free && developer.integer)
1158 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1163 // entity (entity start, .string field, string match) find = #5;
1171 e = G_EDICTNUM(OFS_PARM0);
1172 f = G_INT(OFS_PARM1);
1173 s = G_STRING(OFS_PARM2);
1176 RETURN_EDICT(sv.edicts);
1180 for (e++ ; e < sv.num_edicts ; e++)
1182 pr_xfunction->builtinsprofile++;
1196 RETURN_EDICT(sv.edicts);
1199 // LordHavoc: added this for searching float, int, and entity reference fields
1200 void PF_FindFloat (void)
1207 e = G_EDICTNUM(OFS_PARM0);
1208 f = G_INT(OFS_PARM1);
1209 s = G_FLOAT(OFS_PARM2);
1211 for (e++ ; e < sv.num_edicts ; e++)
1213 pr_xfunction->builtinsprofile++;
1217 if (E_FLOAT(ed,f) == s)
1224 RETURN_EDICT(sv.edicts);
1227 // chained search for strings in entity fields
1228 // entity(.string field, string match) findchain = #402;
1229 void PF_findchain (void)
1234 edict_t *ent, *chain;
1236 chain = (edict_t *)sv.edicts;
1238 f = G_INT(OFS_PARM0);
1239 s = G_STRING(OFS_PARM1);
1242 RETURN_EDICT(sv.edicts);
1246 ent = NEXT_EDICT(sv.edicts);
1247 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1249 pr_xfunction->builtinsprofile++;
1252 t = E_STRING(ent,f);
1258 ent->v->chain = EDICT_TO_PROG(chain);
1262 RETURN_EDICT(chain);
1265 // LordHavoc: chained search for float, int, and entity reference fields
1266 // entity(.string field, float match) findchainfloat = #403;
1267 void PF_findchainfloat (void)
1272 edict_t *ent, *chain;
1274 chain = (edict_t *)sv.edicts;
1276 f = G_INT(OFS_PARM0);
1277 s = G_FLOAT(OFS_PARM1);
1279 ent = NEXT_EDICT(sv.edicts);
1280 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1282 pr_xfunction->builtinsprofile++;
1285 if (E_FLOAT(ent,f) != s)
1288 ent->v->chain = EDICT_TO_PROG(chain);
1292 RETURN_EDICT(chain);
1295 // LordHavoc: search for flags in float fields
1296 void PF_findflags (void)
1303 e = G_EDICTNUM(OFS_PARM0);
1304 f = G_INT(OFS_PARM1);
1305 s = (int)G_FLOAT(OFS_PARM2);
1307 for (e++ ; e < sv.num_edicts ; e++)
1309 pr_xfunction->builtinsprofile++;
1313 if ((int)E_FLOAT(ed,f) & s)
1320 RETURN_EDICT(sv.edicts);
1323 // LordHavoc: chained search for flags in float fields
1324 void PF_findchainflags (void)
1329 edict_t *ent, *chain;
1331 chain = (edict_t *)sv.edicts;
1333 f = G_INT(OFS_PARM0);
1334 s = (int)G_FLOAT(OFS_PARM1);
1336 ent = NEXT_EDICT(sv.edicts);
1337 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1339 pr_xfunction->builtinsprofile++;
1342 if (!((int)E_FLOAT(ent,f) & s))
1345 ent->v->chain = EDICT_TO_PROG(chain);
1349 RETURN_EDICT(chain);
1352 void PR_CheckEmptyString (char *s)
1355 PF_ERROR("Bad string");
1358 void PF_precache_file (void)
1359 { // precache_file is only used to copy files with qcc, it does nothing
1360 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1363 void PF_precache_sound (void)
1367 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
1369 if (sv.state != ss_loading)
1370 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1372 s = G_STRING(OFS_PARM0);
1373 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1374 PR_CheckEmptyString (s);
1376 for (i=0 ; i<limit ; i++)
1378 if (!sv.sound_precache[i])
1380 sv.sound_precache[i] = s;
1383 if (!strcmp(sv.sound_precache[i], s))
1386 PF_ERROR("PF_precache_sound: overflow");
1389 void PF_precache_model (void)
1393 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
1395 if (sv.state != ss_loading)
1396 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1398 s = G_STRING(OFS_PARM0);
1399 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1401 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1402 PR_CheckEmptyString (s);
1404 for (i = 0;i < limit;i++)
1406 if (!sv.model_precache[i])
1408 sv.model_precache[i] = s;
1409 sv.models[i] = Mod_ForName (s, true, false, false);
1412 if (!strcmp(sv.model_precache[i], s))
1415 PF_ERROR("PF_precache_model: overflow");
1419 void PF_coredump (void)
1424 void PF_traceon (void)
1429 void PF_traceoff (void)
1434 void PF_eprint (void)
1436 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1443 float(float yaw, float dist) walkmove
1446 void PF_walkmove (void)
1454 // assume failure if it returns early
1455 G_FLOAT(OFS_RETURN) = 0;
1457 ent = PROG_TO_EDICT(pr_global_struct->self);
1458 if (ent == sv.edicts)
1459 PF_WARNING("walkmove: can not modify world entity\n");
1461 PF_WARNING("walkmove: can not modify free entity\n");
1462 yaw = G_FLOAT(OFS_PARM0);
1463 dist = G_FLOAT(OFS_PARM1);
1465 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1468 yaw = yaw*M_PI*2 / 360;
1470 move[0] = cos(yaw)*dist;
1471 move[1] = sin(yaw)*dist;
1474 // save program state, because SV_movestep may call other progs
1475 oldf = pr_xfunction;
1476 oldself = pr_global_struct->self;
1478 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1481 // restore program state
1482 pr_xfunction = oldf;
1483 pr_global_struct->self = oldself;
1493 void PF_droptofloor (void)
1499 // assume failure if it returns early
1500 G_FLOAT(OFS_RETURN) = 0;
1502 ent = PROG_TO_EDICT(pr_global_struct->self);
1503 if (ent == sv.edicts)
1504 PF_WARNING("droptofloor: can not modify world entity\n");
1506 PF_WARNING("droptofloor: can not modify free entity\n");
1508 VectorCopy (ent->v->origin, end);
1511 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1513 if (trace.fraction != 1)
1515 VectorCopy (trace.endpos, ent->v->origin);
1516 SV_LinkEdict (ent, false);
1517 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1518 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1519 G_FLOAT(OFS_RETURN) = 1;
1520 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1521 ent->e->suspendedinairflag = true;
1529 void(float style, string value) lightstyle
1532 void PF_lightstyle (void)
1539 style = G_FLOAT(OFS_PARM0);
1540 val = G_STRING(OFS_PARM1);
1542 // change the string in sv
1543 sv.lightstyles[style] = val;
1545 // send message to all clients on this server
1546 if (sv.state != ss_active)
1549 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1553 MSG_WriteChar (&client->message, svc_lightstyle);
1554 MSG_WriteChar (&client->message,style);
1555 MSG_WriteString (&client->message, val);
1563 f = G_FLOAT(OFS_PARM0);
1565 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1567 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1569 void PF_floor (void)
1571 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1575 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1584 void PF_checkbottom (void)
1586 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1594 void PF_pointcontents (void)
1596 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1603 entity nextent(entity)
1606 void PF_nextent (void)
1611 i = G_EDICTNUM(OFS_PARM0);
1614 pr_xfunction->builtinsprofile++;
1616 if (i == sv.num_edicts)
1618 RETURN_EDICT(sv.edicts);
1634 Pick a vector for the player to shoot along
1635 vector aim(entity, missilespeed)
1640 edict_t *ent, *check, *bestent;
1641 vec3_t start, dir, end, bestdir;
1644 float dist, bestdist;
1647 // assume failure if it returns early
1648 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1649 // if sv_aim is so high it can't possibly accept anything, skip out early
1650 if (sv_aim.value >= 1)
1653 ent = G_EDICT(OFS_PARM0);
1654 if (ent == sv.edicts)
1655 PF_WARNING("aim: can not use world entity\n");
1657 PF_WARNING("aim: can not use free entity\n");
1658 speed = G_FLOAT(OFS_PARM1);
1660 VectorCopy (ent->v->origin, start);
1663 // try sending a trace straight
1664 VectorCopy (pr_global_struct->v_forward, dir);
1665 VectorMA (start, 2048, dir, end);
1666 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1667 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1668 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1670 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1675 // try all possible entities
1676 VectorCopy (dir, bestdir);
1677 bestdist = sv_aim.value;
1680 check = NEXT_EDICT(sv.edicts);
1681 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1683 pr_xfunction->builtinsprofile++;
1684 if (check->v->takedamage != DAMAGE_AIM)
1688 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1689 continue; // don't aim at teammate
1690 for (j=0 ; j<3 ; j++)
1691 end[j] = check->v->origin[j]
1692 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1693 VectorSubtract (end, start, dir);
1694 VectorNormalize (dir);
1695 dist = DotProduct (dir, pr_global_struct->v_forward);
1696 if (dist < bestdist)
1697 continue; // to far to turn
1698 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1699 if (tr.ent == check)
1700 { // can shoot at this one
1708 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1709 dist = DotProduct (dir, pr_global_struct->v_forward);
1710 VectorScale (pr_global_struct->v_forward, dist, end);
1712 VectorNormalize (end);
1713 VectorCopy (end, G_VECTOR(OFS_RETURN));
1717 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1725 This was a major timewaster in progs, so it was converted to C
1728 void PF_changeyaw (void)
1731 float ideal, current, move, speed;
1733 ent = PROG_TO_EDICT(pr_global_struct->self);
1734 if (ent == sv.edicts)
1735 PF_WARNING("changeyaw: can not modify world entity\n");
1737 PF_WARNING("changeyaw: can not modify free entity\n");
1738 current = ANGLEMOD(ent->v->angles[1]);
1739 ideal = ent->v->ideal_yaw;
1740 speed = ent->v->yaw_speed;
1742 if (current == ideal)
1744 move = ideal - current;
1745 if (ideal > current)
1766 ent->v->angles[1] = ANGLEMOD (current + move);
1774 void PF_changepitch (void)
1777 float ideal, current, move, speed;
1780 ent = G_EDICT(OFS_PARM0);
1781 if (ent == sv.edicts)
1782 PF_WARNING("changepitch: can not modify world entity\n");
1784 PF_WARNING("changepitch: can not modify free entity\n");
1785 current = ANGLEMOD( ent->v->angles[0] );
1786 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1787 ideal = val->_float;
1790 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1793 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1794 speed = val->_float;
1797 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1801 if (current == ideal)
1803 move = ideal - current;
1804 if (ideal > current)
1825 ent->v->angles[0] = ANGLEMOD (current + move);
1829 ===============================================================================
1833 ===============================================================================
1836 #define MSG_BROADCAST 0 // unreliable to all
1837 #define MSG_ONE 1 // reliable to one (msg_entity)
1838 #define MSG_ALL 2 // reliable to all
1839 #define MSG_INIT 3 // write to the init string
1841 sizebuf_t *WriteDest (void)
1847 dest = G_FLOAT(OFS_PARM0);
1851 return &sv.datagram;
1854 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1855 entnum = NUM_FOR_EDICT(ent);
1856 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1857 Host_Error("WriteDest: tried to write to non-client\n");
1858 return &svs.clients[entnum-1].message;
1861 return &sv.reliable_datagram;
1867 Host_Error("WriteDest: bad destination");
1874 void PF_WriteByte (void)
1876 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1879 void PF_WriteChar (void)
1881 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1884 void PF_WriteShort (void)
1886 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1889 void PF_WriteLong (void)
1891 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1894 void PF_WriteAngle (void)
1896 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1899 void PF_WriteCoord (void)
1901 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1904 void PF_WriteString (void)
1906 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1910 void PF_WriteEntity (void)
1912 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1915 //=============================================================================
1917 void PF_makestatic (void)
1922 ent = G_EDICT(OFS_PARM0);
1923 if (ent == sv.edicts)
1924 PF_WARNING("makestatic: can not modify world entity\n");
1926 PF_WARNING("makestatic: can not modify free entity\n");
1929 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1934 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1935 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1936 MSG_WriteShort (&sv.signon, ent->v->frame);
1940 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1941 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1942 MSG_WriteByte (&sv.signon, ent->v->frame);
1945 MSG_WriteByte (&sv.signon, ent->v->colormap);
1946 MSG_WriteByte (&sv.signon, ent->v->skin);
1947 for (i=0 ; i<3 ; i++)
1949 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1950 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1953 // throw the entity away now
1957 //=============================================================================
1964 void PF_setspawnparms (void)
1970 ent = G_EDICT(OFS_PARM0);
1971 i = NUM_FOR_EDICT(ent);
1972 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1974 Con_Print("tried to setspawnparms on a non-client\n");
1978 // copy spawn parms out of the client_t
1979 client = svs.clients + i-1;
1980 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1981 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1989 void PF_changelevel (void)
1993 // make sure we don't issue two changelevels
1994 if (svs.changelevel_issued)
1996 svs.changelevel_issued = true;
1998 s = G_STRING(OFS_PARM0);
1999 Cbuf_AddText (va("changelevel %s\n",s));
2004 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
2009 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
2014 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
2021 Returns a vector of length < 1
2026 void PF_randomvec (void)
2031 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2032 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2033 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2035 while (DotProduct(temp, temp) >= 1);
2036 VectorCopy (temp, G_VECTOR(OFS_RETURN));
2043 Returns a color vector indicating the lighting at the requested point.
2045 (Internal Operation note: actually measures the light beneath the point, just like
2046 the model lighting on the client)
2051 void PF_GetLight (void)
2053 vec3_t ambientcolor, diffusecolor, diffusenormal;
2055 p = G_VECTOR(OFS_PARM0);
2056 VectorClear(ambientcolor);
2057 VectorClear(diffusecolor);
2058 VectorClear(diffusenormal);
2059 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2060 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2061 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2064 void PF_registercvar (void)
2067 name = G_STRING(OFS_PARM0);
2068 value = G_STRING(OFS_PARM1);
2069 G_FLOAT(OFS_RETURN) = 0;
2071 // first check to see if it has already been defined
2072 if (Cvar_FindVar (name))
2075 // check for overlap with a command
2076 if (Cmd_Exists (name))
2078 Con_Printf("PF_registercvar: %s is a command\n", name);
2082 Cvar_Get(name, value, 0);
2084 G_FLOAT(OFS_RETURN) = 1; // success
2091 returns the minimum of two supplied floats
2098 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2100 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2101 else if (pr_argc >= 3)
2104 float f = G_FLOAT(OFS_PARM0);
2105 for (i = 1;i < pr_argc;i++)
2106 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2107 f = G_FLOAT((OFS_PARM0+i*3));
2108 G_FLOAT(OFS_RETURN) = f;
2112 G_FLOAT(OFS_RETURN) = 0;
2113 PF_WARNING("min: must supply at least 2 floats\n");
2121 returns the maximum of two supplied floats
2128 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2130 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2131 else if (pr_argc >= 3)
2134 float f = G_FLOAT(OFS_PARM0);
2135 for (i = 1;i < pr_argc;i++)
2136 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2137 f = G_FLOAT((OFS_PARM0+i*3));
2138 G_FLOAT(OFS_RETURN) = f;
2142 G_FLOAT(OFS_RETURN) = 0;
2143 PF_WARNING("max: must supply at least 2 floats\n");
2151 returns number bounded by supplied range
2153 min(min, value, max)
2156 void PF_bound (void)
2158 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2165 returns a raised to power b
2172 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2179 copies data from one entity to another
2181 copyentity(src, dst)
2184 void PF_copyentity (void)
2187 in = G_EDICT(OFS_PARM0);
2188 if (in == sv.edicts)
2189 PF_WARNING("copyentity: can not read world entity\n");
2191 PF_WARNING("copyentity: can not read free entity\n");
2192 out = G_EDICT(OFS_PARM1);
2193 if (out == sv.edicts)
2194 PF_WARNING("copyentity: can not modify world entity\n");
2196 PF_WARNING("copyentity: can not modify free entity\n");
2197 memcpy(out->v, in->v, progs->entityfields * 4);
2204 sets the color of a client and broadcasts the update to all connected clients
2206 setcolor(clientent, value)
2209 void PF_setcolor (void)
2215 entnum = G_EDICTNUM(OFS_PARM0);
2216 i = G_FLOAT(OFS_PARM1);
2218 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2220 Con_Print("tried to setcolor a non-client\n");
2224 client = svs.clients + entnum-1;
2227 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2229 client->edict->v->team = (i & 15) + 1;
2232 if (client->old_colors != client->colors)
2234 client->old_colors = client->colors;
2235 // send notification to all clients
2236 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2237 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2238 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2246 effect(origin, modelname, startframe, framecount, framerate)
2249 void PF_effect (void)
2253 s = G_STRING(OFS_PARM1);
2255 PF_WARNING("effect: no model specified\n");
2257 i = SV_ModelIndex(s);
2259 PF_WARNING("effect: model not precached\n");
2260 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2263 void PF_te_blood (void)
2265 if (G_FLOAT(OFS_PARM2) < 1)
2267 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2268 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2270 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2272 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2274 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2275 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2276 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2278 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2281 void PF_te_bloodshower (void)
2283 if (G_FLOAT(OFS_PARM3) < 1)
2285 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2286 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2288 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2290 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2292 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2293 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2294 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2296 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2298 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2301 void PF_te_explosionrgb (void)
2303 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2304 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2306 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2310 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2311 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2312 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2315 void PF_te_particlecube (void)
2317 if (G_FLOAT(OFS_PARM3) < 1)
2319 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2320 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2322 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2324 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2326 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2334 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2336 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2337 // gravity true/false
2338 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2340 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2343 void PF_te_particlerain (void)
2345 if (G_FLOAT(OFS_PARM3) < 1)
2347 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2350 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2351 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2352 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2354 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2355 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2356 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2358 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2359 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2360 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2362 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2364 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2367 void PF_te_particlesnow (void)
2369 if (G_FLOAT(OFS_PARM3) < 1)
2371 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2372 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2374 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2375 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2376 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2378 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2382 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2383 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2384 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2386 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2388 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2391 void PF_te_spark (void)
2393 if (G_FLOAT(OFS_PARM2) < 1)
2395 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2396 MSG_WriteByte(&sv.datagram, TE_SPARK);
2398 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2399 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2400 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2402 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2403 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2404 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2406 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2409 void PF_te_gunshotquad (void)
2411 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2412 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2414 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2415 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2416 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2419 void PF_te_spikequad (void)
2421 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2424 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2425 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2426 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2429 void PF_te_superspikequad (void)
2431 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2432 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2434 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2435 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2436 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2439 void PF_te_explosionquad (void)
2441 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2442 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2444 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2445 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2446 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2449 void PF_te_smallflash (void)
2451 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2452 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2454 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2455 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2456 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2459 void PF_te_customflash (void)
2461 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2463 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2464 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2466 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2467 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2468 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2470 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2472 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2474 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2475 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2476 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2479 void PF_te_gunshot (void)
2481 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2482 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2484 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2485 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2486 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2489 void PF_te_spike (void)
2491 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2492 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2494 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2495 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2496 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2499 void PF_te_superspike (void)
2501 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2502 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2504 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2505 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2506 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2509 void PF_te_explosion (void)
2511 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2512 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2514 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2515 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2516 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2519 void PF_te_tarexplosion (void)
2521 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2522 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2524 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2525 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2526 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2529 void PF_te_wizspike (void)
2531 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2532 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2534 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2535 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2536 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2539 void PF_te_knightspike (void)
2541 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2542 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2544 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2545 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2546 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2549 void PF_te_lavasplash (void)
2551 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2552 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2554 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2555 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2556 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2559 void PF_te_teleport (void)
2561 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2562 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2564 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2565 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2566 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2569 void PF_te_explosion2 (void)
2571 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2572 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2574 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2575 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2576 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2578 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2579 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2582 void PF_te_lightning1 (void)
2584 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2585 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2587 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2589 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2591 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2593 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2594 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2595 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2598 void PF_te_lightning2 (void)
2600 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2601 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2603 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2605 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2606 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2607 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2609 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2610 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2611 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2614 void PF_te_lightning3 (void)
2616 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2617 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2619 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2621 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2622 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2623 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2625 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2626 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2627 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2630 void PF_te_beam (void)
2632 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2633 MSG_WriteByte(&sv.datagram, TE_BEAM);
2635 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2637 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2638 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2639 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2641 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2642 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2643 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2646 void PF_te_plasmaburn (void)
2648 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2649 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2650 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2651 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2652 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2655 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2658 vec3_t v1, clipplanenormal, normal;
2659 vec_t clipplanedist, clipdist;
2661 if (surf->flags & SURF_PLANEBACK)
2662 VectorNegate(surf->plane->normal, normal);
2664 VectorCopy(surf->plane->normal, normal);
2665 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2667 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2668 VectorNormalizeFast(v1);
2669 CrossProduct(v1, normal, clipplanenormal);
2670 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2671 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2674 clipdist = -clipdist;
2675 VectorMA(out, clipdist, clipplanenormal, out);
2680 static msurface_t *getsurface(edict_t *ed, int surfnum)
2684 if (!ed || ed->e->free)
2686 modelindex = ed->v->modelindex;
2687 if (modelindex < 1 || modelindex >= MAX_MODELS)
2689 model = sv.models[modelindex];
2690 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2692 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2696 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2697 void PF_getsurfacenumpoints(void)
2700 // return 0 if no such surface
2701 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2703 G_FLOAT(OFS_RETURN) = 0;
2707 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2709 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2710 void PF_getsurfacepoint(void)
2715 VectorClear(G_VECTOR(OFS_RETURN));
2716 ed = G_EDICT(OFS_PARM0);
2717 if (!ed || ed->e->free)
2719 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2721 pointnum = G_FLOAT(OFS_PARM2);
2722 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2724 // FIXME: implement rotation/scaling
2725 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2727 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2728 void PF_getsurfacenormal(void)
2731 VectorClear(G_VECTOR(OFS_RETURN));
2732 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2734 // FIXME: implement rotation/scaling
2735 if (surf->flags & SURF_PLANEBACK)
2736 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2738 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2740 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2741 void PF_getsurfacetexture(void)
2744 G_INT(OFS_RETURN) = 0;
2745 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2747 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2749 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2750 void PF_getsurfacenearpoint(void)
2752 int surfnum, best, modelindex;
2754 vec_t dist, bestdist;
2759 G_FLOAT(OFS_RETURN) = -1;
2760 ed = G_EDICT(OFS_PARM0);
2761 point = G_VECTOR(OFS_PARM1);
2763 if (!ed || ed->e->free)
2765 modelindex = ed->v->modelindex;
2766 if (modelindex < 1 || modelindex >= MAX_MODELS)
2768 model = sv.models[modelindex];
2769 if (!model->brushq1.numsurfaces)
2772 // FIXME: implement rotation/scaling
2773 VectorSubtract(point, ed->v->origin, p);
2775 bestdist = 1000000000;
2776 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2778 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2779 dist = PlaneDiff(p, surf->plane);
2781 if (dist < bestdist)
2783 clippointtosurface(surf, p, clipped);
2784 VectorSubtract(clipped, p, clipped);
2785 dist += DotProduct(clipped, clipped);
2786 if (dist < bestdist)
2793 G_FLOAT(OFS_RETURN) = best;
2795 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2796 void PF_getsurfaceclippedpoint(void)
2801 VectorClear(G_VECTOR(OFS_RETURN));
2802 ed = G_EDICT(OFS_PARM0);
2803 if (!ed || ed->e->free)
2805 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2807 // FIXME: implement rotation/scaling
2808 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2809 clippointtosurface(surf, p, out);
2810 // FIXME: implement rotation/scaling
2811 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2814 #define MAX_PRFILES 256
2816 qfile_t *pr_files[MAX_PRFILES];
2818 void PR_Files_Init(void)
2820 memset(pr_files, 0, sizeof(pr_files));
2823 void PR_Files_CloseAll(void)
2826 for (i = 0;i < MAX_PRFILES;i++)
2829 FS_Close(pr_files[i]);
2834 //float(string s) stof = #81; // get numerical value from a string
2837 char string[STRINGTEMP_LENGTH];
2838 PF_VarString(0, string, sizeof(string));
2839 G_FLOAT(OFS_RETURN) = atof(string);
2842 //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
2845 int filenum, mode, i;
2846 char *modestring, *filename;
2847 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2848 if (pr_files[filenum] == NULL)
2850 if (filenum >= MAX_PRFILES)
2852 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2853 G_FLOAT(OFS_RETURN) = -2;
2856 mode = G_FLOAT(OFS_PARM1);
2859 case 0: // FILE_READ
2862 case 1: // FILE_APPEND
2865 case 2: // FILE_WRITE
2869 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2870 G_FLOAT(OFS_RETURN) = -3;
2873 filename = G_STRING(OFS_PARM0);
2874 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2875 // ../ is parent directory on many platforms
2876 // // is parent directory on Amiga
2877 // / at the beginning of a path is root on unix, and parent directory on Amiga
2878 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2879 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2880 for (i = 0;filename[i];i++)
2882 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2884 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);
2885 G_FLOAT(OFS_RETURN) = -4;
2889 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2891 if (pr_files[filenum] == NULL && modestring == "rb")
2892 pr_files[filenum] = FS_Open(filename, modestring, false);
2894 if (pr_files[filenum] == NULL)
2895 G_FLOAT(OFS_RETURN) = -1;
2897 G_FLOAT(OFS_RETURN) = filenum;
2900 //void(float fhandle) fclose = #111; // closes a file
2901 void PF_fclose(void)
2903 int filenum = G_FLOAT(OFS_PARM0);
2904 if (filenum < 0 || filenum >= MAX_PRFILES)
2906 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2909 if (pr_files[filenum] == NULL)
2911 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2914 FS_Close(pr_files[filenum]);
2915 pr_files[filenum] = NULL;
2918 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2922 static char string[STRINGTEMP_LENGTH];
2923 int filenum = G_FLOAT(OFS_PARM0);
2924 if (filenum < 0 || filenum >= MAX_PRFILES)
2926 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2929 if (pr_files[filenum] == NULL)
2931 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2937 c = FS_Getc(pr_files[filenum]);
2938 if (c == '\r' || c == '\n' || c < 0)
2940 if (end < STRINGTEMP_LENGTH - 1)
2944 // remove \n following \r
2946 c = FS_Getc(pr_files[filenum]);
2947 if (developer.integer)
2948 Con_Printf("fgets: %s\n", string);
2950 G_INT(OFS_RETURN) = PR_SetString(string);
2952 G_INT(OFS_RETURN) = 0;
2955 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2959 char string[STRINGTEMP_LENGTH];
2960 int filenum = G_FLOAT(OFS_PARM0);
2961 if (filenum < 0 || filenum >= MAX_PRFILES)
2963 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2966 if (pr_files[filenum] == NULL)
2968 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2971 PF_VarString(1, string, sizeof(string));
2972 if ((stringlength = strlen(string)))
2973 FS_Write(pr_files[filenum], string, stringlength);
2974 if (developer.integer)
2975 Con_Printf("fputs: %s\n", string);
2978 //float(string s) strlen = #114; // returns how many characters are in a string
2979 void PF_strlen(void)
2982 s = G_STRING(OFS_PARM0);
2984 G_FLOAT(OFS_RETURN) = strlen(s);
2986 G_FLOAT(OFS_RETURN) = 0;
2989 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2990 void PF_strcat(void)
2992 char *s = PR_GetTempString();
2993 PF_VarString(0, s, STRINGTEMP_LENGTH);
2994 G_INT(OFS_RETURN) = PR_SetString(s);
2997 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2998 void PF_substring(void)
3000 int i, start, length;
3001 char *s, *string = PR_GetTempString();
3002 s = G_STRING(OFS_PARM0);
3003 start = G_FLOAT(OFS_PARM1);
3004 length = G_FLOAT(OFS_PARM2);
3007 for (i = 0;i < start && *s;i++, s++);
3008 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3011 G_INT(OFS_RETURN) = PR_SetString(string);
3014 //vector(string s) stov = #117; // returns vector value from a string
3017 char string[STRINGTEMP_LENGTH];
3018 PF_VarString(0, string, sizeof(string));
3019 Math_atov(string, G_VECTOR(OFS_RETURN));
3022 //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)
3023 void PF_strzone(void)
3026 in = G_STRING(OFS_PARM0);
3027 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3029 G_INT(OFS_RETURN) = PR_SetString(out);
3032 //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!!!)
3033 void PF_strunzone(void)
3035 Mem_Free(G_STRING(OFS_PARM0));
3038 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3039 //this function originally written by KrimZon, made shorter by LordHavoc
3040 void PF_clientcommand (void)
3042 client_t *temp_client;
3045 //find client for this entity
3046 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3047 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3049 Con_Print("PF_clientcommand: entity is not a client\n");
3053 temp_client = host_client;
3054 host_client = svs.clients + i;
3055 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3056 host_client = temp_client;
3059 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3060 //this function originally written by KrimZon, made shorter by LordHavoc
3061 //20040203: rewritten by LordHavoc (no longer uses allocations)
3063 char *tokens[256], tokenbuf[4096];
3064 void PF_tokenize (void)
3068 p = G_STRING(OFS_PARM0);
3072 while(COM_ParseToken(&p, false))
3074 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3076 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3078 tokens[num_tokens++] = tokenbuf + pos;
3079 strcpy(tokenbuf + pos, com_token);
3080 pos += strlen(com_token) + 1;
3083 G_FLOAT(OFS_RETURN) = num_tokens;
3086 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3087 //this function originally written by KrimZon, made shorter by LordHavoc
3090 int token_num = G_FLOAT(OFS_PARM0);
3091 if (token_num >= 0 && token_num < num_tokens)
3092 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3094 G_INT(OFS_RETURN) = PR_SetString("");
3097 //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)
3098 void PF_setattachment (void)
3100 edict_t *e = G_EDICT(OFS_PARM0);
3101 edict_t *tagentity = G_EDICT(OFS_PARM1);
3102 char *tagname = G_STRING(OFS_PARM2);
3108 PF_WARNING("setattachment: can not modify world entity\n");
3110 PF_WARNING("setattachment: can not modify free entity\n");
3112 if (tagentity == NULL)
3113 tagentity = sv.edicts;
3115 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3117 v->edict = EDICT_TO_PROG(tagentity);
3119 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3122 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3124 modelindex = (int)tagentity->v->modelindex;
3125 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3127 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3128 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3129 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3131 // FIXME: use a model function to get tag info (need to handle skeletal)
3132 if (v->_float == 0 && model->alias.aliasnum_tags)
3133 for (i = 0;i < model->alias.aliasnum_tags;i++)
3134 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3137 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);
3140 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));
3144 /////////////////////////////////////////
3145 // DP_MD3_TAGINFO extension coded by VorteX
3147 int SV_GetTagIndex (edict_t *e, char *tagname)
3152 model = sv.models[(int)e->v->modelindex];
3155 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3157 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3159 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3168 for (i = 0;i < model->alias.aliasnum_tags; i++)
3170 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3177 return tagindex + 1;
3180 // Warnings/errors code:
3181 // 0 - normal (everything all-right)
3184 // 3 - null or non-precached model
3185 // 4 - no tags with requested index
3186 // 5 - runaway loop at attachment chain
3187 extern cvar_t cl_bob;
3188 extern cvar_t cl_bobcycle;
3189 extern cvar_t cl_bobup;
3190 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3193 int modelindex, reqtag, reqframe, attachloop;
3194 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3198 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3200 if (ent == sv.edicts)
3205 modelindex = (int)ent->v->modelindex;
3206 if (modelindex <= 0 || modelindex > MAX_MODELS)
3209 model = sv.models[modelindex];
3210 reqtag = model->alias.aliasnum_tags;
3212 if (tagindex <= 0 || tagindex > reqtag)
3214 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3219 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3220 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3222 reqframe = ent->v->frame;
3224 // get initial tag matrix
3227 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3228 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3231 Matrix4x4_CreateIdentity(&tagmatrix);
3233 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3234 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3238 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3239 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3241 {// got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3242 model = sv.models[(int)attachent->v->modelindex];
3243 reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3244 Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3247 Matrix4x4_CreateIdentity(&attachmatrix);
3249 // apply transformation by child entity matrix
3250 val = GETEDICTFIELDVALUE(ent, eval_scale);
3251 if (val->_float == 0)
3253 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], val->_float);
3254 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3255 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3256 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3257 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3258 Matrix4x4_Copy(&tagmatrix, out);
3260 // finally transformate by matrix of tag on parent entity
3261 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3262 out->m[0][3] = attachmatrix.m[0][3] + attachmatrix.m[0][0]*tagmatrix.m[0][3] + attachmatrix.m[0][1]*tagmatrix.m[1][3] + attachmatrix.m[0][2]*tagmatrix.m[2][3];
3263 out->m[1][3] = attachmatrix.m[1][3] + attachmatrix.m[1][0]*tagmatrix.m[0][3] + attachmatrix.m[1][1]*tagmatrix.m[1][3] + attachmatrix.m[1][2]*tagmatrix.m[2][3];
3264 out->m[2][3] = attachmatrix.m[2][3] + attachmatrix.m[2][0]*tagmatrix.m[0][3] + attachmatrix.m[2][1]*tagmatrix.m[1][3] + attachmatrix.m[2][2]*tagmatrix.m[2][3];
3265 Matrix4x4_Copy(&tagmatrix, out);
3269 if (attachloop > 255) // prevent runaway looping
3272 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3275 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3276 val = GETEDICTFIELDVALUE(ent, eval_scale);
3277 if (val->_float == 0)
3279 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3280 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], val->_float);
3281 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3282 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3283 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3284 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3286 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3287 {// RENDER_VIEWMODEL magic
3288 Matrix4x4_Copy(&tagmatrix, out);
3289 ent = EDICT_NUM(val->edict);
3291 val = GETEDICTFIELDVALUE(ent, eval_scale);
3292 if (val->_float == 0)
3295 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], val->_float);
3296 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3297 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3298 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3299 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3302 // Cl_bob, ported from rendering code
3303 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3306 // LordHavoc: this code is *weird*, but not replacable (I think it
3307 // should be done in QC on the server, but oh well, quake is quake)
3308 // LordHavoc: figured out bobup: the time at which the sin is at 180
3309 // degrees (which allows lengthening or squishing the peak or valley)
3310 cycle = sv.time/cl_bobcycle.value;
3311 cycle -= (int)cycle;
3312 if (cycle < cl_bobup.value)
3313 cycle = sin(M_PI * cycle / cl_bobup.value);
3315 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3316 // bob is proportional to velocity in the xy plane
3317 // (don't count Z, or jumping messes it up)
3318 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3319 bob = bob*0.3 + bob*0.7*cycle;
3320 out->m[2][3] += bound(-7, bob, 4);
3327 //float(entity ent, string tagname) gettagindex;
3329 void PF_gettagindex (void)
3331 edict_t *ent = G_EDICT(OFS_PARM0);
3332 char *tag_name = G_STRING(OFS_PARM1);
3333 int modelindex, tag_index;
3335 if (ent == sv.edicts)
3336 PF_WARNING("gettagindex: can't affect world entity\n");
3338 PF_WARNING("gettagindex: can't affect free entity\n");
3340 modelindex = (int)ent->v->modelindex;
3342 if (modelindex <= 0 || modelindex > MAX_MODELS)
3343 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3346 tag_index = SV_GetTagIndex(ent, tag_name);
3348 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3350 G_FLOAT(OFS_RETURN) = tag_index;
3353 //vector(entity ent, float tagindex) gettaginfo;
3354 void PF_gettaginfo (void)
3356 edict_t *e = G_EDICT(OFS_PARM0);
3357 int tagindex = (int)G_FLOAT(OFS_PARM1);
3358 matrix4x4_t tag_matrix;
3361 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3362 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3367 PF_WARNING("gettagindex: can't affect world entity\n");
3370 PF_WARNING("gettagindex: can't affect free entity\n");
3373 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3376 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3379 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3385 /////////////////////////////////////////
3386 // DP_QC_FS_SEARCH extension
3388 // qc fs search handling
3389 #define MAX_SEARCHES 128
3391 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3393 void PR_Search_Init(void)
3395 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3398 void PR_Search_Reset(void)
3401 // reset the fssearch list
3402 for(i = 0; i < MAX_SEARCHES; i++)
3403 if(pr_fssearchlist[i])
3404 FS_FreeSearch(pr_fssearchlist[i]);
3405 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3412 float search_begin(string pattern, float caseinsensitive, float quiet)
3415 void PF_search_begin(void)
3419 int caseinsens, quiet;
3421 pattern = G_STRING(OFS_PARM0);
3423 PR_CheckEmptyString(pattern);
3425 caseinsens = G_FLOAT(OFS_PARM1);
3426 quiet = G_FLOAT(OFS_PARM2);
3428 for(handle = 0; handle < MAX_SEARCHES; handle++)
3429 if(!pr_fssearchlist[handle])
3432 if(handle >= MAX_SEARCHES)
3434 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3435 G_FLOAT(OFS_RETURN) = -2;
3439 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3440 G_FLOAT(OFS_RETURN) = -1;
3442 G_FLOAT(OFS_RETURN) = handle;
3449 void search_end(float handle)
3452 void PF_search_end(void)
3456 handle = G_FLOAT(OFS_PARM0);
3458 if(handle < 0 || handle >= MAX_SEARCHES)
3460 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3463 if(pr_fssearchlist[handle] == NULL)
3465 Con_Printf("PF_search_end: no such handle %i\n", handle);
3469 FS_FreeSearch(pr_fssearchlist[handle]);
3470 pr_fssearchlist[handle] = NULL;
3477 float search_getsize(float handle)
3480 void PF_search_getsize(void)
3484 handle = G_FLOAT(OFS_PARM0);
3486 if(handle < 0 || handle >= MAX_SEARCHES)
3488 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3491 if(pr_fssearchlist[handle] == NULL)
3493 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3497 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3502 VM_search_getfilename
3504 string search_getfilename(float handle, float num)
3507 void PF_search_getfilename(void)
3509 int handle, filenum;
3512 handle = G_FLOAT(OFS_PARM0);
3513 filenum = G_FLOAT(OFS_PARM1);
3515 if(handle < 0 || handle >= MAX_SEARCHES)
3517 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3520 if(pr_fssearchlist[handle] == NULL)
3522 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3525 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3527 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3531 tmp = PR_GetTempString();
3532 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3534 G_INT(OFS_RETURN) = PR_SetString(tmp);
3537 void PF_cvar_string (void)
3543 str = G_STRING(OFS_PARM0);
3544 var = Cvar_FindVar (str);
3547 tmp = PR_GetTempString();
3548 strcpy(tmp, var->string);
3552 G_INT(OFS_RETURN) = PR_SetString(tmp);
3555 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3556 void PF_dropclient (void)
3559 client_t *oldhostclient;
3560 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3561 if (clientnum < 0 || clientnum >= svs.maxclients)
3562 PF_WARNING("dropclient: not a client\n");
3563 if (!svs.clients[clientnum].active)
3564 PF_WARNING("dropclient: that client slot is not connected\n");
3565 oldhostclient = host_client;
3566 host_client = svs.clients + clientnum;
3567 SV_DropClient(false);
3568 host_client = oldhostclient;
3571 //entity() spawnclient (DP_SV_BOTCLIENT)
3572 void PF_spawnclient (void)
3576 pr_xfunction->builtinsprofile += 2;
3578 for (i = 0;i < svs.maxclients;i++)
3580 if (!svs.clients[i].active)
3582 pr_xfunction->builtinsprofile += 100;
3583 SV_ConnectClient (i, NULL);
3584 ed = EDICT_NUM(i + 1);
3591 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3592 void PF_clienttype (void)
3595 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3596 if (clientnum < 0 || clientnum >= svs.maxclients)
3597 G_FLOAT(OFS_RETURN) = 3;
3598 else if (!svs.clients[clientnum].active)
3599 G_FLOAT(OFS_RETURN) = 0;
3600 else if (svs.clients[clientnum].netconnection)
3601 G_FLOAT(OFS_RETURN) = 1;
3603 G_FLOAT(OFS_RETURN) = 2;
3606 builtin_t pr_builtin[] =
3609 PF_makevectors, // #1 void(entity e) makevectors
3610 PF_setorigin, // #2 void(entity e, vector o) setorigin
3611 PF_setmodel, // #3 void(entity e, string m) setmodel
3612 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3613 NULL, // #5 void(entity e, vector min, vector max) setabssize
3614 PF_break, // #6 void() break
3615 PF_random, // #7 float() random
3616 PF_sound, // #8 void(entity e, float chan, string samp) sound
3617 PF_normalize, // #9 vector(vector v) normalize
3618 PF_error, // #10 void(string e) error
3619 PF_objerror, // #11 void(string e) objerror
3620 PF_vlen, // #12 float(vector v) vlen
3621 PF_vectoyaw, // #13 float(vector v) vectoyaw
3622 PF_Spawn, // #14 entity() spawn
3623 PF_Remove, // #15 void(entity e) remove
3624 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3625 PF_checkclient, // #17 entity() clientlist
3626 PF_Find, // #18 entity(entity start, .string fld, string match) find
3627 PF_precache_sound, // #19 void(string s) precache_sound
3628 PF_precache_model, // #20 void(string s) precache_model
3629 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3630 PF_findradius, // #22 entity(vector org, float rad) findradius
3631 PF_bprint, // #23 void(string s) bprint
3632 PF_sprint, // #24 void(entity client, string s) sprint
3633 PF_dprint, // #25 void(string s) dprint
3634 PF_ftos, // #26 void(string s) ftos
3635 PF_vtos, // #27 void(string s) vtos
3636 PF_coredump, // #28 void() coredump
3637 PF_traceon, // #29 void() traceon
3638 PF_traceoff, // #30 void() traceoff
3639 PF_eprint, // #31 void(entity e) eprint
3640 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3642 PF_droptofloor, // #34 float() droptofloor
3643 PF_lightstyle, // #35 void(float style, string value) lightstyle
3644 PF_rint, // #36 float(float v) rint
3645 PF_floor, // #37 float(float v) floor
3646 PF_ceil, // #38 float(float v) ceil
3648 PF_checkbottom, // #40 float(entity e) checkbottom
3649 PF_pointcontents, // #41 float(vector v) pointcontents
3651 PF_fabs, // #43 float(float f) fabs
3652 PF_aim, // #44 vector(entity e, float speed) aim
3653 PF_cvar, // #45 float(string s) cvar
3654 PF_localcmd, // #46 void(string s) localcmd
3655 PF_nextent, // #47 entity(entity e) nextent
3656 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3657 PF_changeyaw, // #49 void() ChangeYaw
3659 PF_vectoangles, // #51 vector(vector v) vectoangles
3660 PF_WriteByte, // #52 void(float to, float f) WriteByte
3661 PF_WriteChar, // #53 void(float to, float f) WriteChar
3662 PF_WriteShort, // #54 void(float to, float f) WriteShort
3663 PF_WriteLong, // #55 void(float to, float f) WriteLong
3664 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3665 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3666 PF_WriteString, // #58 void(float to, string s) WriteString
3667 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3668 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3669 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3670 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3671 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3672 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3673 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3675 SV_MoveToGoal, // #67 void(float step) movetogoal
3676 PF_precache_file, // #68 string(string s) precache_file
3677 PF_makestatic, // #69 void(entity e) makestatic
3678 PF_changelevel, // #70 void(string s) changelevel
3680 PF_cvar_set, // #72 void(string var, string val) cvar_set
3681 PF_centerprint, // #73 void(entity client, strings) centerprint
3682 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3683 PF_precache_model, // #75 string(string s) precache_model2
3684 PF_precache_sound, // #76 string(string s) precache_sound2
3685 PF_precache_file, // #77 string(string s) precache_file2
3686 PF_setspawnparms, // #78 void(entity e) setspawnparms
3689 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3698 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3699 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3700 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3701 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3702 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3703 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3704 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3705 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3706 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3707 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3718 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3719 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3720 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3721 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3722 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3723 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3724 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3725 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3726 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3727 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3728 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3729 a a a a a a a a // #120-199
3730 a a a a a a a a a a // #200-299
3731 a a a a a a a a a a // #300-399
3732 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3733 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3734 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3735 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3736 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3737 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3738 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3739 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3740 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3741 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3742 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3743 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3744 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3745 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3746 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3747 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3748 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3749 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3750 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3751 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3752 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3753 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3754 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3755 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3756 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3757 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3758 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3759 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3760 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3761 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3762 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3763 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3764 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3765 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3766 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3767 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3768 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3769 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3770 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3771 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3772 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3773 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3774 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3775 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3776 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3777 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3778 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3779 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3780 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3781 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3782 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3783 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3784 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3785 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3786 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3787 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3792 a a a a // #460-499 (LordHavoc)
3795 builtin_t *pr_builtins = pr_builtin;
3796 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3798 void PR_Cmd_Init(void)
3800 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3805 void PR_Cmd_Reset(void)
3807 Mem_EmptyPool(pr_strings_mempool);
3809 PR_Files_CloseAll();