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_CLIENTCOLORS "
138 "DP_SV_DRAWONLYTOCLIENT "
141 "DP_SV_NODRAWTOCLIENT "
143 "DP_SV_PLAYERPHYSICS "
145 "DP_SV_ROTATINGBMODEL "
151 "DP_TE_EXPLOSIONRGB "
153 "DP_TE_PARTICLECUBE "
154 "DP_TE_PARTICLERAIN "
155 "DP_TE_PARTICLESNOW "
157 "DP_TE_QUADEFFECTS1 "
160 "DP_TE_STANDARDEFFECTBUILTINS "
163 "KRIMZON_SV_PARSECLIENTCOMMAND "
167 "TENEBRAE_GFX_DLIGHTS "
171 qboolean checkextension(char *name)
176 for (e = ENGINE_EXTENSIONS;*e;e++)
183 while (*e && *e != ' ')
185 if (e - start == len)
186 if (!strncasecmp(start, name, len))
196 returns true if the extension is supported by the server
198 checkextension(extensionname)
201 void PF_checkextension (void)
203 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
210 This is a TERMINAL error, which will kill off the entire server.
219 char string[STRINGTEMP_LENGTH];
221 PF_VarString(0, string, sizeof(string));
222 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
223 ed = PROG_TO_EDICT(pr_global_struct->self);
226 PF_ERROR("Program error");
233 Dumps out self, then an error message. The program is aborted and self is
234 removed, but the level can continue.
239 void PF_objerror (void)
242 char string[STRINGTEMP_LENGTH];
244 PF_VarString(0, string, sizeof(string));
245 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
246 ed = PROG_TO_EDICT(pr_global_struct->self);
256 Writes new values for v_forward, v_up, and v_right based on angles
260 void PF_makevectors (void)
262 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
269 Writes new values for v_forward, v_up, and v_right based on the given forward vector
270 vectorvectors(vector, vector)
273 void PF_vectorvectors (void)
275 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
276 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
283 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.
285 setorigin (entity, origin)
288 void PF_setorigin (void)
293 e = G_EDICT(OFS_PARM0);
295 PF_WARNING("setorigin: can not modify world entity\n");
297 PF_WARNING("setorigin: can not modify free entity\n");
298 org = G_VECTOR(OFS_PARM1);
299 VectorCopy (org, e->v->origin);
300 SV_LinkEdict (e, false);
304 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
308 for (i=0 ; i<3 ; i++)
310 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
312 // set derived values
313 VectorCopy (min, e->v->mins);
314 VectorCopy (max, e->v->maxs);
315 VectorSubtract (max, min, e->v->size);
317 SV_LinkEdict (e, false);
324 the size box is rotated by the current angle
325 LordHavoc: no it isn't...
327 setsize (entity, minvector, maxvector)
330 void PF_setsize (void)
335 e = G_EDICT(OFS_PARM0);
337 PF_WARNING("setsize: can not modify world entity\n");
339 PF_WARNING("setsize: can not modify free entity\n");
340 min = G_VECTOR(OFS_PARM1);
341 max = G_VECTOR(OFS_PARM2);
342 SetMinMaxSize (e, min, max, false);
350 setmodel(entity, model)
353 void PF_setmodel (void)
360 e = G_EDICT(OFS_PARM0);
362 PF_WARNING("setmodel: can not modify world entity\n");
364 PF_WARNING("setmodel: can not modify free entity\n");
365 m = G_STRING(OFS_PARM1);
367 // check to see if model was properly precached
368 for (i=0, check = sv.model_precache ; *check ; i++, check++)
369 if (!strcmp(*check, m))
373 PF_WARNING(va("setmodel: no precache for model \"%s\"\n", m));
376 e->v->model = PR_SetString(*check);
377 e->v->modelindex = i;
379 mod = sv.models[ (int)e->v->modelindex];
382 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
384 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
391 broadcast print to everyone on server
396 void PF_bprint (void)
398 char string[STRINGTEMP_LENGTH];
399 PF_VarString(0, string, sizeof(string));
400 SV_BroadcastPrint(string);
407 single print to a specific client
409 sprint(clientent, value)
412 void PF_sprint (void)
416 char string[STRINGTEMP_LENGTH];
418 entnum = G_EDICTNUM(OFS_PARM0);
420 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
422 Con_Print("tried to sprint to a non-client\n");
426 client = svs.clients + entnum-1;
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 PF_VarString(1, string, sizeof(string));
458 MSG_WriteChar(&client->message,svc_centerprint);
459 MSG_WriteString(&client->message, string);
467 vector normalize(vector)
470 void PF_normalize (void)
476 value1 = G_VECTOR(OFS_PARM0);
478 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
482 newvalue[0] = newvalue[1] = newvalue[2] = 0;
486 newvalue[0] = value1[0] * new;
487 newvalue[1] = value1[1] * new;
488 newvalue[2] = value1[2] * new;
491 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
506 value1 = G_VECTOR(OFS_PARM0);
508 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
511 G_FLOAT(OFS_RETURN) = new;
518 float vectoyaw(vector)
521 void PF_vectoyaw (void)
526 value1 = G_VECTOR(OFS_PARM0);
528 if (value1[1] == 0 && value1[0] == 0)
532 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
537 G_FLOAT(OFS_RETURN) = yaw;
545 vector vectoangles(vector)
548 void PF_vectoangles (void)
550 double value1[3], forward, yaw, pitch;
552 VectorCopy(G_VECTOR(OFS_PARM0), value1);
554 if (value1[1] == 0 && value1[0] == 0)
564 // LordHavoc: optimized a bit
567 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
571 else if (value1[1] > 0)
576 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
577 pitch = (atan2(value1[2], forward) * 180 / M_PI);
582 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
589 Returns a number from 0<= num < 1
594 void PF_random (void)
598 num = (rand ()&0x7fff) / ((float)0x7fff);
600 G_FLOAT(OFS_RETURN) = num;
607 particle(origin, color, count)
610 void PF_particle (void)
616 org = G_VECTOR(OFS_PARM0);
617 dir = G_VECTOR(OFS_PARM1);
618 color = G_FLOAT(OFS_PARM2);
619 count = G_FLOAT(OFS_PARM3);
620 SV_StartParticle (org, dir, color, count);
630 void PF_ambientsound (void)
635 float vol, attenuation;
638 pos = G_VECTOR (OFS_PARM0);
639 samp = G_STRING(OFS_PARM1);
640 vol = G_FLOAT(OFS_PARM2);
641 attenuation = G_FLOAT(OFS_PARM3);
643 // check to see if samp was properly precached
644 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
645 if (!strcmp(*check,samp))
650 Con_Printf("no precache: %s\n", samp);
658 // add an svc_spawnambient command to the level signon packet
661 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
663 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
665 MSG_WriteVector(&sv.signon, pos, sv.protocol);
668 MSG_WriteShort (&sv.signon, soundnum);
670 MSG_WriteByte (&sv.signon, soundnum);
672 MSG_WriteByte (&sv.signon, vol*255);
673 MSG_WriteByte (&sv.signon, attenuation*64);
681 Each entity can have eight independant sound sources, like voice,
684 Channel 0 is an auto-allocate channel, the others override anything
685 already running on that entity/channel pair.
687 An attenuation of 0 will play full volume everywhere in the level.
688 Larger attenuations will drop off.
700 entity = G_EDICT(OFS_PARM0);
701 channel = G_FLOAT(OFS_PARM1);
702 sample = G_STRING(OFS_PARM2);
703 volume = G_FLOAT(OFS_PARM3) * 255;
704 attenuation = G_FLOAT(OFS_PARM4);
706 if (volume < 0 || volume > 255)
707 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
709 if (attenuation < 0 || attenuation > 4)
710 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
712 if (channel < 0 || channel > 7)
713 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
715 SV_StartSound (entity, channel, sample, volume, attenuation);
727 PF_ERROR("break: break statement\n");
734 Used for use tracing and shot targeting
735 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
736 if the tryents flag is set.
738 traceline (vector1, vector2, tryents)
741 void PF_traceline (void)
748 pr_xfunction->builtinsprofile += 30;
750 v1 = G_VECTOR(OFS_PARM0);
751 v2 = G_VECTOR(OFS_PARM1);
752 move = G_FLOAT(OFS_PARM2);
753 ent = G_EDICT(OFS_PARM3);
755 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
757 pr_global_struct->trace_allsolid = trace.allsolid;
758 pr_global_struct->trace_startsolid = trace.startsolid;
759 pr_global_struct->trace_fraction = trace.fraction;
760 pr_global_struct->trace_inwater = trace.inwater;
761 pr_global_struct->trace_inopen = trace.inopen;
762 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
763 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
764 pr_global_struct->trace_plane_dist = trace.plane.dist;
766 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
768 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
769 // FIXME: add trace_endcontents
777 Used for use tracing and shot targeting
778 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
779 if the tryents flag is set.
781 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
784 // LordHavoc: added this for my own use, VERY useful, similar to traceline
785 void PF_tracebox (void)
787 float *v1, *v2, *m1, *m2;
792 pr_xfunction->builtinsprofile += 30;
794 v1 = G_VECTOR(OFS_PARM0);
795 m1 = G_VECTOR(OFS_PARM1);
796 m2 = G_VECTOR(OFS_PARM2);
797 v2 = G_VECTOR(OFS_PARM3);
798 move = G_FLOAT(OFS_PARM4);
799 ent = G_EDICT(OFS_PARM5);
801 trace = SV_Move (v1, m1, m2, v2, move, ent);
803 pr_global_struct->trace_allsolid = trace.allsolid;
804 pr_global_struct->trace_startsolid = trace.startsolid;
805 pr_global_struct->trace_fraction = trace.fraction;
806 pr_global_struct->trace_inwater = trace.inwater;
807 pr_global_struct->trace_inopen = trace.inopen;
808 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
809 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
810 pr_global_struct->trace_plane_dist = trace.plane.dist;
812 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
814 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
817 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
818 void PF_TraceToss (void)
824 pr_xfunction->builtinsprofile += 600;
826 ent = G_EDICT(OFS_PARM0);
827 if (ent == sv.edicts)
828 PF_WARNING("tracetoss: can not use world entity\n");
829 ignore = G_EDICT(OFS_PARM1);
831 trace = SV_Trace_Toss (ent, ignore);
833 pr_global_struct->trace_allsolid = trace.allsolid;
834 pr_global_struct->trace_startsolid = trace.startsolid;
835 pr_global_struct->trace_fraction = trace.fraction;
836 pr_global_struct->trace_inwater = trace.inwater;
837 pr_global_struct->trace_inopen = trace.inopen;
838 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
839 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
840 pr_global_struct->trace_plane_dist = trace.plane.dist;
842 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
844 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
852 Returns true if the given entity can move to the given position from it's
853 current position by walking or rolling.
855 scalar checkpos (entity, vector)
858 void PF_checkpos (void)
862 //============================================================================
865 qbyte checkpvs[MAX_MAP_LEAFS/8];
867 int PF_newcheckclient (int check)
873 // cycle to the next one
875 check = bound(1, check, svs.maxclients);
876 if (check == svs.maxclients)
884 pr_xfunction->builtinsprofile++;
886 if (i == svs.maxclients+1)
888 // look up the client's edict
890 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
891 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
893 // found a valid client (possibly the same one again)
897 // get the PVS for the entity
898 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
900 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
901 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
910 Returns a client (or object that has a client enemy) that would be a
913 If there is more than one valid option, they are cycled each frame
915 If (self.origin + self.viewofs) is not in the PVS of the current target,
916 it is not returned at all.
921 int c_invis, c_notvis;
922 void PF_checkclient (void)
927 // find a new check if on a new frame
928 if (sv.time - sv.lastchecktime >= 0.1)
930 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
931 sv.lastchecktime = sv.time;
934 // return check if it might be visible
935 ent = EDICT_NUM(sv.lastcheck);
936 if (ent->e->free || ent->v->health <= 0)
938 RETURN_EDICT(sv.edicts);
942 // if current entity can't possibly see the check entity, return 0
943 self = PROG_TO_EDICT(pr_global_struct->self);
944 VectorAdd(self->v->origin, self->v->view_ofs, view);
945 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
948 RETURN_EDICT(sv.edicts);
952 // might be able to see it
957 //============================================================================
964 Sends text over to the client's execution buffer
966 stuffcmd (clientent, value)
969 void PF_stuffcmd (void)
975 entnum = G_EDICTNUM(OFS_PARM0);
976 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
978 Con_Print("Can't stuffcmd to a non-client\n");
981 str = G_STRING(OFS_PARM1);
984 host_client = svs.clients + entnum-1;
985 Host_ClientCommands ("%s", str);
993 Sends text to server console
998 void PF_localcmd (void)
1000 Cbuf_AddText(G_STRING(OFS_PARM0));
1012 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1022 void PF_cvar_set (void)
1024 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1031 Returns a chain of entities that have origins within a spherical area
1033 findradius (origin, radius)
1036 void PF_findradius (void)
1038 edict_t *ent, *chain;
1039 vec_t radius, radius2;
1040 vec3_t org, eorg, mins, maxs;
1043 edict_t *touchedicts[MAX_EDICTS];
1045 chain = (edict_t *)sv.edicts;
1047 VectorCopy(G_VECTOR(OFS_PARM0), org);
1048 radius = G_FLOAT(OFS_PARM1);
1049 radius2 = radius * radius;
1051 mins[0] = org[0] - radius;
1052 mins[1] = org[1] - radius;
1053 mins[2] = org[2] - radius;
1054 maxs[0] = org[0] + radius;
1055 maxs[1] = org[1] + radius;
1056 maxs[2] = org[2] + radius;
1057 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1058 if (numtouchedicts > MAX_EDICTS)
1060 // this never happens
1061 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1062 numtouchedicts = MAX_EDICTS;
1064 for (i = 0;i < numtouchedicts;i++)
1066 ent = touchedicts[i];
1067 pr_xfunction->builtinsprofile++;
1068 // LordHavoc: compare against bounding box rather than center so it
1069 // doesn't miss large objects, and use DotProduct instead of Length
1070 // for a major speedup
1071 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1072 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1073 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1074 if (DotProduct(eorg, eorg) < radius2)
1076 ent->v->chain = EDICT_TO_PROG(chain);
1081 RETURN_EDICT(chain);
1090 void PF_dprint (void)
1092 char string[STRINGTEMP_LENGTH];
1093 if (developer.integer)
1095 PF_VarString(0, string, sizeof(string));
1104 v = G_FLOAT(OFS_PARM0);
1106 s = PR_GetTempString();
1107 if ((float)((int)v) == v)
1108 sprintf(s, "%i", (int)v);
1110 sprintf(s, "%f", v);
1111 G_INT(OFS_RETURN) = PR_SetString(s);
1117 v = G_FLOAT(OFS_PARM0);
1118 G_FLOAT(OFS_RETURN) = fabs(v);
1124 s = PR_GetTempString();
1125 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1126 G_INT(OFS_RETURN) = PR_SetString(s);
1132 s = PR_GetTempString();
1133 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1134 G_INT(OFS_RETURN) = PR_SetString(s);
1137 void PF_Spawn (void)
1140 pr_xfunction->builtinsprofile += 20;
1145 void PF_Remove (void)
1148 pr_xfunction->builtinsprofile += 20;
1150 ed = G_EDICT(OFS_PARM0);
1151 if (ed == sv.edicts)
1152 PF_WARNING("remove: tried to remove world\n");
1153 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1154 PF_WARNING("remove: tried to remove a client\n");
1155 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1156 if (ed->e->free && developer.integer)
1157 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1162 // entity (entity start, .string field, string match) find = #5;
1170 e = G_EDICTNUM(OFS_PARM0);
1171 f = G_INT(OFS_PARM1);
1172 s = G_STRING(OFS_PARM2);
1175 RETURN_EDICT(sv.edicts);
1179 for (e++ ; e < sv.num_edicts ; e++)
1181 pr_xfunction->builtinsprofile++;
1195 RETURN_EDICT(sv.edicts);
1198 // LordHavoc: added this for searching float, int, and entity reference fields
1199 void PF_FindFloat (void)
1206 e = G_EDICTNUM(OFS_PARM0);
1207 f = G_INT(OFS_PARM1);
1208 s = G_FLOAT(OFS_PARM2);
1210 for (e++ ; e < sv.num_edicts ; e++)
1212 pr_xfunction->builtinsprofile++;
1216 if (E_FLOAT(ed,f) == s)
1223 RETURN_EDICT(sv.edicts);
1226 // chained search for strings in entity fields
1227 // entity(.string field, string match) findchain = #402;
1228 void PF_findchain (void)
1233 edict_t *ent, *chain;
1235 chain = (edict_t *)sv.edicts;
1237 f = G_INT(OFS_PARM0);
1238 s = G_STRING(OFS_PARM1);
1241 RETURN_EDICT(sv.edicts);
1245 ent = NEXT_EDICT(sv.edicts);
1246 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1248 pr_xfunction->builtinsprofile++;
1251 t = E_STRING(ent,f);
1257 ent->v->chain = EDICT_TO_PROG(chain);
1261 RETURN_EDICT(chain);
1264 // LordHavoc: chained search for float, int, and entity reference fields
1265 // entity(.string field, float match) findchainfloat = #403;
1266 void PF_findchainfloat (void)
1271 edict_t *ent, *chain;
1273 chain = (edict_t *)sv.edicts;
1275 f = G_INT(OFS_PARM0);
1276 s = G_FLOAT(OFS_PARM1);
1278 ent = NEXT_EDICT(sv.edicts);
1279 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1281 pr_xfunction->builtinsprofile++;
1284 if (E_FLOAT(ent,f) != s)
1287 ent->v->chain = EDICT_TO_PROG(chain);
1291 RETURN_EDICT(chain);
1294 // LordHavoc: search for flags in float fields
1295 void PF_findflags (void)
1302 e = G_EDICTNUM(OFS_PARM0);
1303 f = G_INT(OFS_PARM1);
1304 s = (int)G_FLOAT(OFS_PARM2);
1306 for (e++ ; e < sv.num_edicts ; e++)
1308 pr_xfunction->builtinsprofile++;
1312 if ((int)E_FLOAT(ed,f) & s)
1319 RETURN_EDICT(sv.edicts);
1322 // LordHavoc: chained search for flags in float fields
1323 void PF_findchainflags (void)
1328 edict_t *ent, *chain;
1330 chain = (edict_t *)sv.edicts;
1332 f = G_INT(OFS_PARM0);
1333 s = (int)G_FLOAT(OFS_PARM1);
1335 ent = NEXT_EDICT(sv.edicts);
1336 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1338 pr_xfunction->builtinsprofile++;
1341 if (!((int)E_FLOAT(ent,f) & s))
1344 ent->v->chain = EDICT_TO_PROG(chain);
1348 RETURN_EDICT(chain);
1351 void PR_CheckEmptyString (char *s)
1354 PF_ERROR("Bad string");
1357 void PF_precache_file (void)
1358 { // precache_file is only used to copy files with qcc, it does nothing
1359 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1362 void PF_precache_sound (void)
1366 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
1368 if (sv.state != ss_loading)
1369 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1371 s = G_STRING(OFS_PARM0);
1372 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1373 PR_CheckEmptyString (s);
1375 for (i=0 ; i<limit ; i++)
1377 if (!sv.sound_precache[i])
1379 sv.sound_precache[i] = s;
1382 if (!strcmp(sv.sound_precache[i], s))
1385 PF_ERROR("PF_precache_sound: overflow");
1388 void PF_precache_model (void)
1392 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
1394 if (sv.state != ss_loading)
1395 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1397 s = G_STRING(OFS_PARM0);
1398 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1400 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1401 PR_CheckEmptyString (s);
1403 for (i = 0;i < limit;i++)
1405 if (!sv.model_precache[i])
1407 sv.model_precache[i] = s;
1408 sv.models[i] = Mod_ForName (s, true, false, false);
1411 if (!strcmp(sv.model_precache[i], s))
1414 PF_ERROR("PF_precache_model: overflow");
1418 void PF_coredump (void)
1423 void PF_traceon (void)
1428 void PF_traceoff (void)
1433 void PF_eprint (void)
1435 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1442 float(float yaw, float dist) walkmove
1445 void PF_walkmove (void)
1453 // assume failure if it returns early
1454 G_FLOAT(OFS_RETURN) = 0;
1456 ent = PROG_TO_EDICT(pr_global_struct->self);
1457 if (ent == sv.edicts)
1458 PF_WARNING("walkmove: can not modify world entity\n");
1460 PF_WARNING("walkmove: can not modify free entity\n");
1461 yaw = G_FLOAT(OFS_PARM0);
1462 dist = G_FLOAT(OFS_PARM1);
1464 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1467 yaw = yaw*M_PI*2 / 360;
1469 move[0] = cos(yaw)*dist;
1470 move[1] = sin(yaw)*dist;
1473 // save program state, because SV_movestep may call other progs
1474 oldf = pr_xfunction;
1475 oldself = pr_global_struct->self;
1477 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1480 // restore program state
1481 pr_xfunction = oldf;
1482 pr_global_struct->self = oldself;
1492 void PF_droptofloor (void)
1498 // assume failure if it returns early
1499 G_FLOAT(OFS_RETURN) = 0;
1501 ent = PROG_TO_EDICT(pr_global_struct->self);
1502 if (ent == sv.edicts)
1503 PF_WARNING("droptofloor: can not modify world entity\n");
1505 PF_WARNING("droptofloor: can not modify free entity\n");
1507 VectorCopy (ent->v->origin, end);
1510 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1512 if (trace.fraction != 1)
1514 VectorCopy (trace.endpos, ent->v->origin);
1515 SV_LinkEdict (ent, false);
1516 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1517 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1518 G_FLOAT(OFS_RETURN) = 1;
1519 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1520 ent->e->suspendedinairflag = true;
1528 void(float style, string value) lightstyle
1531 void PF_lightstyle (void)
1538 style = G_FLOAT(OFS_PARM0);
1539 val = G_STRING(OFS_PARM1);
1541 // change the string in sv
1542 sv.lightstyles[style] = val;
1544 // send message to all clients on this server
1545 if (sv.state != ss_active)
1548 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1552 MSG_WriteChar (&client->message, svc_lightstyle);
1553 MSG_WriteChar (&client->message,style);
1554 MSG_WriteString (&client->message, val);
1562 f = G_FLOAT(OFS_PARM0);
1564 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1566 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1568 void PF_floor (void)
1570 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1574 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1583 void PF_checkbottom (void)
1585 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1593 void PF_pointcontents (void)
1595 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1602 entity nextent(entity)
1605 void PF_nextent (void)
1610 i = G_EDICTNUM(OFS_PARM0);
1613 pr_xfunction->builtinsprofile++;
1615 if (i == sv.num_edicts)
1617 RETURN_EDICT(sv.edicts);
1633 Pick a vector for the player to shoot along
1634 vector aim(entity, missilespeed)
1639 edict_t *ent, *check, *bestent;
1640 vec3_t start, dir, end, bestdir;
1643 float dist, bestdist;
1646 // assume failure if it returns early
1647 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1648 // if sv_aim is so high it can't possibly accept anything, skip out early
1649 if (sv_aim.value >= 1)
1652 ent = G_EDICT(OFS_PARM0);
1653 if (ent == sv.edicts)
1654 PF_WARNING("aim: can not use world entity\n");
1656 PF_WARNING("aim: can not use free entity\n");
1657 speed = G_FLOAT(OFS_PARM1);
1659 VectorCopy (ent->v->origin, start);
1662 // try sending a trace straight
1663 VectorCopy (pr_global_struct->v_forward, dir);
1664 VectorMA (start, 2048, dir, end);
1665 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1666 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1667 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1669 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1674 // try all possible entities
1675 VectorCopy (dir, bestdir);
1676 bestdist = sv_aim.value;
1679 check = NEXT_EDICT(sv.edicts);
1680 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1682 pr_xfunction->builtinsprofile++;
1683 if (check->v->takedamage != DAMAGE_AIM)
1687 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1688 continue; // don't aim at teammate
1689 for (j=0 ; j<3 ; j++)
1690 end[j] = check->v->origin[j]
1691 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1692 VectorSubtract (end, start, dir);
1693 VectorNormalize (dir);
1694 dist = DotProduct (dir, pr_global_struct->v_forward);
1695 if (dist < bestdist)
1696 continue; // to far to turn
1697 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1698 if (tr.ent == check)
1699 { // can shoot at this one
1707 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1708 dist = DotProduct (dir, pr_global_struct->v_forward);
1709 VectorScale (pr_global_struct->v_forward, dist, end);
1711 VectorNormalize (end);
1712 VectorCopy (end, G_VECTOR(OFS_RETURN));
1716 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1724 This was a major timewaster in progs, so it was converted to C
1727 void PF_changeyaw (void)
1730 float ideal, current, move, speed;
1732 ent = PROG_TO_EDICT(pr_global_struct->self);
1733 if (ent == sv.edicts)
1734 PF_WARNING("changeyaw: can not modify world entity\n");
1736 PF_WARNING("changeyaw: can not modify free entity\n");
1737 current = ANGLEMOD(ent->v->angles[1]);
1738 ideal = ent->v->ideal_yaw;
1739 speed = ent->v->yaw_speed;
1741 if (current == ideal)
1743 move = ideal - current;
1744 if (ideal > current)
1765 ent->v->angles[1] = ANGLEMOD (current + move);
1773 void PF_changepitch (void)
1776 float ideal, current, move, speed;
1779 ent = G_EDICT(OFS_PARM0);
1780 if (ent == sv.edicts)
1781 PF_WARNING("changepitch: can not modify world entity\n");
1783 PF_WARNING("changepitch: can not modify free entity\n");
1784 current = ANGLEMOD( ent->v->angles[0] );
1785 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1786 ideal = val->_float;
1789 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1792 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1793 speed = val->_float;
1796 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1800 if (current == ideal)
1802 move = ideal - current;
1803 if (ideal > current)
1824 ent->v->angles[0] = ANGLEMOD (current + move);
1828 ===============================================================================
1832 ===============================================================================
1835 #define MSG_BROADCAST 0 // unreliable to all
1836 #define MSG_ONE 1 // reliable to one (msg_entity)
1837 #define MSG_ALL 2 // reliable to all
1838 #define MSG_INIT 3 // write to the init string
1840 sizebuf_t *WriteDest (void)
1846 dest = G_FLOAT(OFS_PARM0);
1850 return &sv.datagram;
1853 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1854 entnum = NUM_FOR_EDICT(ent);
1855 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1856 Host_Error("WriteDest: tried to write to non-client\n");
1857 return &svs.clients[entnum-1].message;
1860 return &sv.reliable_datagram;
1866 Host_Error("WriteDest: bad destination");
1873 void PF_WriteByte (void)
1875 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1878 void PF_WriteChar (void)
1880 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1883 void PF_WriteShort (void)
1885 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1888 void PF_WriteLong (void)
1890 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1893 void PF_WriteAngle (void)
1895 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1898 void PF_WriteCoord (void)
1900 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1903 void PF_WriteString (void)
1905 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1909 void PF_WriteEntity (void)
1911 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1914 //=============================================================================
1916 void PF_makestatic (void)
1921 ent = G_EDICT(OFS_PARM0);
1922 if (ent == sv.edicts)
1923 PF_WARNING("makestatic: can not modify world entity\n");
1925 PF_WARNING("makestatic: can not modify free entity\n");
1928 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1933 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1934 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1935 MSG_WriteShort (&sv.signon, ent->v->frame);
1939 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1940 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1941 MSG_WriteByte (&sv.signon, ent->v->frame);
1944 MSG_WriteByte (&sv.signon, ent->v->colormap);
1945 MSG_WriteByte (&sv.signon, ent->v->skin);
1946 for (i=0 ; i<3 ; i++)
1948 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1949 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1952 // throw the entity away now
1956 //=============================================================================
1963 void PF_setspawnparms (void)
1969 ent = G_EDICT(OFS_PARM0);
1970 i = NUM_FOR_EDICT(ent);
1971 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1973 Con_Print("tried to setspawnparms on a non-client\n");
1977 // copy spawn parms out of the client_t
1978 client = svs.clients + i-1;
1979 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1980 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1988 void PF_changelevel (void)
1992 // make sure we don't issue two changelevels
1993 if (svs.changelevel_issued)
1995 svs.changelevel_issued = true;
1997 s = G_STRING(OFS_PARM0);
1998 Cbuf_AddText (va("changelevel %s\n",s));
2003 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
2008 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
2013 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
2020 Returns a vector of length < 1
2025 void PF_randomvec (void)
2030 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2031 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2032 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2034 while (DotProduct(temp, temp) >= 1);
2035 VectorCopy (temp, G_VECTOR(OFS_RETURN));
2042 Returns a color vector indicating the lighting at the requested point.
2044 (Internal Operation note: actually measures the light beneath the point, just like
2045 the model lighting on the client)
2050 void PF_GetLight (void)
2052 vec3_t ambientcolor, diffusecolor, diffusenormal;
2054 p = G_VECTOR(OFS_PARM0);
2055 VectorClear(ambientcolor);
2056 VectorClear(diffusecolor);
2057 VectorClear(diffusenormal);
2058 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2059 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2060 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2063 void PF_registercvar (void)
2066 name = G_STRING(OFS_PARM0);
2067 value = G_STRING(OFS_PARM1);
2068 G_FLOAT(OFS_RETURN) = 0;
2070 // first check to see if it has already been defined
2071 if (Cvar_FindVar (name))
2074 // check for overlap with a command
2075 if (Cmd_Exists (name))
2077 Con_Printf("PF_registercvar: %s is a command\n", name);
2081 Cvar_Get(name, value, 0);
2083 G_FLOAT(OFS_RETURN) = 1; // success
2090 returns the minimum of two supplied floats
2097 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2099 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2100 else if (pr_argc >= 3)
2103 float f = G_FLOAT(OFS_PARM0);
2104 for (i = 1;i < pr_argc;i++)
2105 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2106 f = G_FLOAT((OFS_PARM0+i*3));
2107 G_FLOAT(OFS_RETURN) = f;
2111 G_FLOAT(OFS_RETURN) = 0;
2112 PF_WARNING("min: must supply at least 2 floats\n");
2120 returns the maximum of two supplied floats
2127 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2129 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2130 else if (pr_argc >= 3)
2133 float f = G_FLOAT(OFS_PARM0);
2134 for (i = 1;i < pr_argc;i++)
2135 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2136 f = G_FLOAT((OFS_PARM0+i*3));
2137 G_FLOAT(OFS_RETURN) = f;
2141 G_FLOAT(OFS_RETURN) = 0;
2142 PF_WARNING("max: must supply at least 2 floats\n");
2150 returns number bounded by supplied range
2152 min(min, value, max)
2155 void PF_bound (void)
2157 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2164 returns a raised to power b
2171 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2178 copies data from one entity to another
2180 copyentity(src, dst)
2183 void PF_copyentity (void)
2186 in = G_EDICT(OFS_PARM0);
2187 if (in == sv.edicts)
2188 PF_WARNING("copyentity: can not read world entity\n");
2190 PF_WARNING("copyentity: can not read free entity\n");
2191 out = G_EDICT(OFS_PARM1);
2192 if (out == sv.edicts)
2193 PF_WARNING("copyentity: can not modify world entity\n");
2195 PF_WARNING("copyentity: can not modify free entity\n");
2196 memcpy(out->v, in->v, progs->entityfields * 4);
2203 sets the color of a client and broadcasts the update to all connected clients
2205 setcolor(clientent, value)
2208 void PF_setcolor (void)
2214 entnum = G_EDICTNUM(OFS_PARM0);
2215 i = G_FLOAT(OFS_PARM1);
2217 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2219 Con_Print("tried to setcolor a non-client\n");
2223 client = svs.clients + entnum-1;
2226 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2228 client->edict->v->team = (i & 15) + 1;
2231 if (client->old_colors != client->colors)
2233 client->old_colors = client->colors;
2234 // send notification to all clients
2235 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2236 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2237 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2245 effect(origin, modelname, startframe, framecount, framerate)
2248 void PF_effect (void)
2252 s = G_STRING(OFS_PARM1);
2254 PF_WARNING("effect: no model specified\n");
2256 i = SV_ModelIndex(s);
2258 PF_WARNING("effect: model not precached\n");
2259 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2262 void PF_te_blood (void)
2264 if (G_FLOAT(OFS_PARM2) < 1)
2266 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2267 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2269 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2273 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2274 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2275 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2277 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2280 void PF_te_bloodshower (void)
2282 if (G_FLOAT(OFS_PARM3) < 1)
2284 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2285 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2287 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2288 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2291 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2292 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2293 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2295 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2297 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2300 void PF_te_explosionrgb (void)
2302 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2303 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2305 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2309 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2310 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2311 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2314 void PF_te_particlecube (void)
2316 if (G_FLOAT(OFS_PARM3) < 1)
2318 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2319 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2321 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2322 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2325 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2326 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2333 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2335 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2336 // gravity true/false
2337 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2339 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2342 void PF_te_particlerain (void)
2344 if (G_FLOAT(OFS_PARM3) < 1)
2346 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2347 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2349 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2350 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2351 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2353 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2354 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2355 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2357 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2358 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2359 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2361 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2363 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2366 void PF_te_particlesnow (void)
2368 if (G_FLOAT(OFS_PARM3) < 1)
2370 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2371 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2373 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2374 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2375 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2377 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2378 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2381 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2382 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2383 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2385 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2387 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2390 void PF_te_spark (void)
2392 if (G_FLOAT(OFS_PARM2) < 1)
2394 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2395 MSG_WriteByte(&sv.datagram, TE_SPARK);
2397 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2398 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2399 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2401 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2402 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2403 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2405 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2408 void PF_te_gunshotquad (void)
2410 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2411 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2413 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2414 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2415 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2418 void PF_te_spikequad (void)
2420 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2421 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2423 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2424 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2425 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2428 void PF_te_superspikequad (void)
2430 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2431 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2433 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2434 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2435 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2438 void PF_te_explosionquad (void)
2440 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2441 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2443 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2444 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2445 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2448 void PF_te_smallflash (void)
2450 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2451 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2453 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2454 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2455 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2458 void PF_te_customflash (void)
2460 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2462 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2463 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2465 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2466 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2467 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2469 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2471 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2473 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2474 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2475 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2478 void PF_te_gunshot (void)
2480 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2481 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2483 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2484 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2485 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2488 void PF_te_spike (void)
2490 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2491 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2493 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2494 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2495 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2498 void PF_te_superspike (void)
2500 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2501 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2503 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2504 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2505 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2508 void PF_te_explosion (void)
2510 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2511 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2513 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2514 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2515 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2518 void PF_te_tarexplosion (void)
2520 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2521 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2523 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2524 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2525 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2528 void PF_te_wizspike (void)
2530 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2531 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2533 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2534 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2535 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2538 void PF_te_knightspike (void)
2540 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2541 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2543 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2544 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2545 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2548 void PF_te_lavasplash (void)
2550 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2551 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2553 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2554 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2555 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2558 void PF_te_teleport (void)
2560 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2561 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2563 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2564 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2565 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2568 void PF_te_explosion2 (void)
2570 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2571 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2573 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2574 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2575 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2577 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2578 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2581 void PF_te_lightning1 (void)
2583 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2584 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2586 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2588 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2589 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2592 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2593 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2594 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2597 void PF_te_lightning2 (void)
2599 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2600 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2602 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2604 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2605 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2606 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2608 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2609 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2610 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2613 void PF_te_lightning3 (void)
2615 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2616 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2618 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2620 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2621 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2622 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2624 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2625 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2626 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2629 void PF_te_beam (void)
2631 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2632 MSG_WriteByte(&sv.datagram, TE_BEAM);
2634 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2636 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2637 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2638 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2640 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2641 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2642 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2645 void PF_te_plasmaburn (void)
2647 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2648 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2649 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2650 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2651 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2654 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2657 vec3_t v1, clipplanenormal, normal;
2658 vec_t clipplanedist, clipdist;
2660 if (surf->flags & SURF_PLANEBACK)
2661 VectorNegate(surf->plane->normal, normal);
2663 VectorCopy(surf->plane->normal, normal);
2664 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2666 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2667 VectorNormalizeFast(v1);
2668 CrossProduct(v1, normal, clipplanenormal);
2669 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2670 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2673 clipdist = -clipdist;
2674 VectorMA(out, clipdist, clipplanenormal, out);
2679 static msurface_t *getsurface(edict_t *ed, int surfnum)
2683 if (!ed || ed->e->free)
2685 modelindex = ed->v->modelindex;
2686 if (modelindex < 1 || modelindex >= MAX_MODELS)
2688 model = sv.models[modelindex];
2689 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2691 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2695 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2696 void PF_getsurfacenumpoints(void)
2699 // return 0 if no such surface
2700 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2702 G_FLOAT(OFS_RETURN) = 0;
2706 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2708 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2709 void PF_getsurfacepoint(void)
2714 VectorClear(G_VECTOR(OFS_RETURN));
2715 ed = G_EDICT(OFS_PARM0);
2716 if (!ed || ed->e->free)
2718 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2720 pointnum = G_FLOAT(OFS_PARM2);
2721 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2723 // FIXME: implement rotation/scaling
2724 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2726 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2727 void PF_getsurfacenormal(void)
2730 VectorClear(G_VECTOR(OFS_RETURN));
2731 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2733 // FIXME: implement rotation/scaling
2734 if (surf->flags & SURF_PLANEBACK)
2735 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2737 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2739 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2740 void PF_getsurfacetexture(void)
2743 G_INT(OFS_RETURN) = 0;
2744 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2746 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2748 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2749 void PF_getsurfacenearpoint(void)
2751 int surfnum, best, modelindex;
2753 vec_t dist, bestdist;
2758 G_FLOAT(OFS_RETURN) = -1;
2759 ed = G_EDICT(OFS_PARM0);
2760 point = G_VECTOR(OFS_PARM1);
2762 if (!ed || ed->e->free)
2764 modelindex = ed->v->modelindex;
2765 if (modelindex < 1 || modelindex >= MAX_MODELS)
2767 model = sv.models[modelindex];
2768 if (!model->brushq1.numsurfaces)
2771 // FIXME: implement rotation/scaling
2772 VectorSubtract(point, ed->v->origin, p);
2774 bestdist = 1000000000;
2775 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2777 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2778 dist = PlaneDiff(p, surf->plane);
2780 if (dist < bestdist)
2782 clippointtosurface(surf, p, clipped);
2783 VectorSubtract(clipped, p, clipped);
2784 dist += DotProduct(clipped, clipped);
2785 if (dist < bestdist)
2792 G_FLOAT(OFS_RETURN) = best;
2794 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2795 void PF_getsurfaceclippedpoint(void)
2800 VectorClear(G_VECTOR(OFS_RETURN));
2801 ed = G_EDICT(OFS_PARM0);
2802 if (!ed || ed->e->free)
2804 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2806 // FIXME: implement rotation/scaling
2807 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2808 clippointtosurface(surf, p, out);
2809 // FIXME: implement rotation/scaling
2810 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2813 #define MAX_PRFILES 256
2815 qfile_t *pr_files[MAX_PRFILES];
2817 void PR_Files_Init(void)
2819 memset(pr_files, 0, sizeof(pr_files));
2822 void PR_Files_CloseAll(void)
2825 for (i = 0;i < MAX_PRFILES;i++)
2828 FS_Close(pr_files[i]);
2833 //float(string s) stof = #81; // get numerical value from a string
2836 char string[STRINGTEMP_LENGTH];
2837 PF_VarString(0, string, sizeof(string));
2838 G_FLOAT(OFS_RETURN) = atof(string);
2841 //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
2844 int filenum, mode, i;
2845 char *modestring, *filename;
2846 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2847 if (pr_files[filenum] == NULL)
2849 if (filenum >= MAX_PRFILES)
2851 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2852 G_FLOAT(OFS_RETURN) = -2;
2855 mode = G_FLOAT(OFS_PARM1);
2858 case 0: // FILE_READ
2861 case 1: // FILE_APPEND
2864 case 2: // FILE_WRITE
2868 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2869 G_FLOAT(OFS_RETURN) = -3;
2872 filename = G_STRING(OFS_PARM0);
2873 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2874 // ../ is parent directory on many platforms
2875 // // is parent directory on Amiga
2876 // / at the beginning of a path is root on unix, and parent directory on Amiga
2877 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2878 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2879 for (i = 0;filename[i];i++)
2881 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2883 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);
2884 G_FLOAT(OFS_RETURN) = -4;
2888 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2890 if (pr_files[filenum] == NULL && modestring == "rb")
2891 pr_files[filenum] = FS_Open(filename, modestring, false);
2893 if (pr_files[filenum] == NULL)
2894 G_FLOAT(OFS_RETURN) = -1;
2896 G_FLOAT(OFS_RETURN) = filenum;
2899 //void(float fhandle) fclose = #111; // closes a file
2900 void PF_fclose(void)
2902 int filenum = G_FLOAT(OFS_PARM0);
2903 if (filenum < 0 || filenum >= MAX_PRFILES)
2905 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2908 if (pr_files[filenum] == NULL)
2910 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2913 FS_Close(pr_files[filenum]);
2914 pr_files[filenum] = NULL;
2917 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2921 static char string[STRINGTEMP_LENGTH];
2922 int filenum = G_FLOAT(OFS_PARM0);
2923 if (filenum < 0 || filenum >= MAX_PRFILES)
2925 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2928 if (pr_files[filenum] == NULL)
2930 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2936 c = FS_Getc(pr_files[filenum]);
2937 if (c == '\r' || c == '\n' || c < 0)
2939 if (end < STRINGTEMP_LENGTH - 1)
2943 // remove \n following \r
2945 c = FS_Getc(pr_files[filenum]);
2946 if (developer.integer)
2947 Con_Printf("fgets: %s\n", string);
2949 G_INT(OFS_RETURN) = PR_SetString(string);
2951 G_INT(OFS_RETURN) = 0;
2954 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2958 char string[STRINGTEMP_LENGTH];
2959 int filenum = G_FLOAT(OFS_PARM0);
2960 if (filenum < 0 || filenum >= MAX_PRFILES)
2962 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2965 if (pr_files[filenum] == NULL)
2967 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2970 PF_VarString(1, string, sizeof(string));
2971 if ((stringlength = strlen(string)))
2972 FS_Write(pr_files[filenum], string, stringlength);
2973 if (developer.integer)
2974 Con_Printf("fputs: %s\n", string);
2977 //float(string s) strlen = #114; // returns how many characters are in a string
2978 void PF_strlen(void)
2981 s = G_STRING(OFS_PARM0);
2983 G_FLOAT(OFS_RETURN) = strlen(s);
2985 G_FLOAT(OFS_RETURN) = 0;
2988 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2989 void PF_strcat(void)
2991 char *s = PR_GetTempString();
2992 PF_VarString(0, s, STRINGTEMP_LENGTH);
2993 G_INT(OFS_RETURN) = PR_SetString(s);
2996 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2997 void PF_substring(void)
2999 int i, start, length;
3000 char *s, *string = PR_GetTempString();
3001 s = G_STRING(OFS_PARM0);
3002 start = G_FLOAT(OFS_PARM1);
3003 length = G_FLOAT(OFS_PARM2);
3006 for (i = 0;i < start && *s;i++, s++);
3007 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3010 G_INT(OFS_RETURN) = PR_SetString(string);
3013 //vector(string s) stov = #117; // returns vector value from a string
3016 char string[STRINGTEMP_LENGTH];
3017 PF_VarString(0, string, sizeof(string));
3018 Math_atov(string, G_VECTOR(OFS_RETURN));
3021 //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)
3022 void PF_strzone(void)
3025 in = G_STRING(OFS_PARM0);
3026 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3028 G_INT(OFS_RETURN) = PR_SetString(out);
3031 //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!!!)
3032 void PF_strunzone(void)
3034 Mem_Free(G_STRING(OFS_PARM0));
3037 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3038 //this function originally written by KrimZon, made shorter by LordHavoc
3039 void PF_clientcommand (void)
3041 client_t *temp_client;
3044 //find client for this entity
3045 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3046 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3048 Con_Print("PF_clientcommand: entity is not a client\n");
3052 temp_client = host_client;
3053 host_client = svs.clients + i;
3054 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3055 host_client = temp_client;
3058 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3059 //this function originally written by KrimZon, made shorter by LordHavoc
3060 //20040203: rewritten by LordHavoc (no longer uses allocations)
3062 char *tokens[256], tokenbuf[4096];
3063 void PF_tokenize (void)
3067 p = G_STRING(OFS_PARM0);
3071 while(COM_ParseToken(&p, false))
3073 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3075 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3077 tokens[num_tokens++] = tokenbuf + pos;
3078 strcpy(tokenbuf + pos, com_token);
3079 pos += strlen(com_token) + 1;
3082 G_FLOAT(OFS_RETURN) = num_tokens;
3085 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3086 //this function originally written by KrimZon, made shorter by LordHavoc
3089 int token_num = G_FLOAT(OFS_PARM0);
3090 if (token_num >= 0 && token_num < num_tokens)
3091 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3093 G_INT(OFS_RETURN) = PR_SetString("");
3096 //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)
3097 void PF_setattachment (void)
3099 edict_t *e = G_EDICT(OFS_PARM0);
3100 edict_t *tagentity = G_EDICT(OFS_PARM1);
3101 char *tagname = G_STRING(OFS_PARM2);
3107 PF_WARNING("setattachment: can not modify world entity\n");
3109 PF_WARNING("setattachment: can not modify free entity\n");
3111 if (tagentity == NULL)
3112 tagentity = sv.edicts;
3114 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3116 v->edict = EDICT_TO_PROG(tagentity);
3118 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3121 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3123 modelindex = (int)tagentity->v->modelindex;
3124 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3126 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3127 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3128 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3130 // FIXME: use a model function to get tag info (need to handle skeletal)
3131 if (v->_float == 0 && model->alias.aliasnum_tags)
3132 for (i = 0;i < model->alias.aliasnum_tags;i++)
3133 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3136 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);
3139 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));
3143 /////////////////////////////////////////
3144 // DP_MD3_TAGINFO extension coded by VorteX
3146 int SV_GetTagIndex (edict_t *e, char *tagname)
3151 model = sv.models[(int)e->v->modelindex];
3154 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3156 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3158 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3167 for (i = 0;i < model->alias.aliasnum_tags; i++)
3169 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3176 return tagindex + 1;
3179 // Warnings/errors code:
3180 // 0 - normal (everything all-right)
3183 // 3 - null or non-precached model
3184 // 4 - no tags with requested index
3185 // 5 - runaway loop at attachment chain
3186 extern cvar_t cl_bob;
3187 extern cvar_t cl_bobcycle;
3188 extern cvar_t cl_bobup;
3189 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3192 int modelindex, reqtag, reqframe, attachloop;
3193 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3197 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3199 if (ent == sv.edicts)
3204 modelindex = (int)ent->v->modelindex;
3205 if (modelindex <= 0 || modelindex > MAX_MODELS)
3208 model = sv.models[modelindex];
3209 reqtag = model->alias.aliasnum_tags;
3211 if (tagindex <= 0 || tagindex > reqtag)
3213 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3218 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3219 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3221 reqframe = ent->v->frame;
3223 // get initial tag matrix
3226 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3227 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3230 Matrix4x4_CreateIdentity(&tagmatrix);
3232 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3233 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3237 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3238 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3240 {// got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3241 model = sv.models[(int)attachent->v->modelindex];
3242 reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3243 Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3246 Matrix4x4_CreateIdentity(&attachmatrix);
3248 // apply transformation by child entity matrix
3249 val = GETEDICTFIELDVALUE(ent, eval_scale);
3250 if (val->_float == 0)
3252 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);
3253 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3254 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]);
3255 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]);
3256 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]);
3257 Matrix4x4_Copy(&tagmatrix, out);
3259 // finally transformate by matrix of tag on parent entity
3260 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3261 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];
3262 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];
3263 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];
3264 Matrix4x4_Copy(&tagmatrix, out);
3268 if (attachloop > 255) // prevent runaway looping
3271 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3274 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3275 val = GETEDICTFIELDVALUE(ent, eval_scale);
3276 if (val->_float == 0)
3278 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3279 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);
3280 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3281 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]);
3282 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]);
3283 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]);
3285 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3286 {// RENDER_VIEWMODEL magic
3287 Matrix4x4_Copy(&tagmatrix, out);
3288 ent = EDICT_NUM(val->edict);
3290 val = GETEDICTFIELDVALUE(ent, eval_scale);
3291 if (val->_float == 0)
3294 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);
3295 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3296 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]);
3297 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]);
3298 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]);
3301 // Cl_bob, ported from rendering code
3302 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3305 // LordHavoc: this code is *weird*, but not replacable (I think it
3306 // should be done in QC on the server, but oh well, quake is quake)
3307 // LordHavoc: figured out bobup: the time at which the sin is at 180
3308 // degrees (which allows lengthening or squishing the peak or valley)
3309 cycle = sv.time/cl_bobcycle.value;
3310 cycle -= (int)cycle;
3311 if (cycle < cl_bobup.value)
3312 cycle = sin(M_PI * cycle / cl_bobup.value);
3314 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3315 // bob is proportional to velocity in the xy plane
3316 // (don't count Z, or jumping messes it up)
3317 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3318 bob = bob*0.3 + bob*0.7*cycle;
3319 out->m[2][3] += bound(-7, bob, 4);
3326 //float(entity ent, string tagname) gettagindex;
3328 void PF_gettagindex (void)
3330 edict_t *ent = G_EDICT(OFS_PARM0);
3331 char *tag_name = G_STRING(OFS_PARM1);
3332 int modelindex, tag_index;
3334 if (ent == sv.edicts)
3335 PF_WARNING("gettagindex: can't affect world entity\n");
3337 PF_WARNING("gettagindex: can't affect free entity\n");
3339 modelindex = (int)ent->v->modelindex;
3341 if (modelindex <= 0 || modelindex > MAX_MODELS)
3342 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3345 tag_index = SV_GetTagIndex(ent, tag_name);
3347 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3349 G_FLOAT(OFS_RETURN) = tag_index;
3352 //vector(entity ent, float tagindex) gettaginfo;
3353 void PF_gettaginfo (void)
3355 edict_t *e = G_EDICT(OFS_PARM0);
3356 int tagindex = (int)G_FLOAT(OFS_PARM1);
3357 matrix4x4_t tag_matrix;
3360 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3361 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3366 PF_WARNING("gettagindex: can't affect world entity\n");
3369 PF_WARNING("gettagindex: can't affect free entity\n");
3372 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3375 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3378 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3384 /////////////////////////////////////////
3385 // DP_QC_FS_SEARCH extension
3387 // qc fs search handling
3388 #define MAX_SEARCHES 128
3390 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3392 void PR_Search_Init(void)
3394 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3397 void PR_Search_Reset(void)
3400 // reset the fssearch list
3401 for(i = 0; i < MAX_SEARCHES; i++)
3402 if(pr_fssearchlist[i])
3403 FS_FreeSearch(pr_fssearchlist[i]);
3404 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3411 float search_begin(string pattern, float caseinsensitive, float quiet)
3414 void PF_search_begin(void)
3418 int caseinsens, quiet;
3420 pattern = G_STRING(OFS_PARM0);
3422 PR_CheckEmptyString(pattern);
3424 caseinsens = G_FLOAT(OFS_PARM1);
3425 quiet = G_FLOAT(OFS_PARM2);
3427 for(handle = 0; handle < MAX_SEARCHES; handle++)
3428 if(!pr_fssearchlist[handle])
3431 if(handle >= MAX_SEARCHES)
3433 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3434 G_FLOAT(OFS_RETURN) = -2;
3438 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3439 G_FLOAT(OFS_RETURN) = -1;
3441 G_FLOAT(OFS_RETURN) = handle;
3448 void search_end(float handle)
3451 void PF_search_end(void)
3455 handle = G_FLOAT(OFS_PARM0);
3457 if(handle < 0 || handle >= MAX_SEARCHES)
3459 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3462 if(pr_fssearchlist[handle] == NULL)
3464 Con_Printf("PF_search_end: no such handle %i\n", handle);
3468 FS_FreeSearch(pr_fssearchlist[handle]);
3469 pr_fssearchlist[handle] = NULL;
3476 float search_getsize(float handle)
3479 void PF_search_getsize(void)
3483 handle = G_FLOAT(OFS_PARM0);
3485 if(handle < 0 || handle >= MAX_SEARCHES)
3487 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3490 if(pr_fssearchlist[handle] == NULL)
3492 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3496 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3501 VM_search_getfilename
3503 string search_getfilename(float handle, float num)
3506 void PF_search_getfilename(void)
3508 int handle, filenum;
3511 handle = G_FLOAT(OFS_PARM0);
3512 filenum = G_FLOAT(OFS_PARM1);
3514 if(handle < 0 || handle >= MAX_SEARCHES)
3516 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3519 if(pr_fssearchlist[handle] == NULL)
3521 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3524 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3526 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3530 tmp = PR_GetTempString();
3531 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3533 G_INT(OFS_RETURN) = PR_SetString(tmp);
3536 void PF_cvar_string (void)
3542 str = G_STRING(OFS_PARM0);
3543 var = Cvar_FindVar (str);
3546 tmp = PR_GetTempString();
3547 strcpy(tmp, var->string);
3551 G_INT(OFS_RETURN) = PR_SetString(tmp);
3554 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3555 void PF_dropclient (void)
3558 client_t *oldhostclient;
3559 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3560 if (clientnum < 0 || clientnum >= svs.maxclients)
3561 PF_WARNING("dropclient: not a client\n");
3562 if (!svs.clients[clientnum].active)
3563 PF_WARNING("dropclient: that client slot is not connected\n");
3564 oldhostclient = host_client;
3565 host_client = svs.clients + clientnum;
3566 SV_DropClient(false);
3567 host_client = oldhostclient;
3571 builtin_t pr_builtin[] =
3574 PF_makevectors, // #1 void(entity e) makevectors
3575 PF_setorigin, // #2 void(entity e, vector o) setorigin
3576 PF_setmodel, // #3 void(entity e, string m) setmodel
3577 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3578 NULL, // #5 void(entity e, vector min, vector max) setabssize
3579 PF_break, // #6 void() break
3580 PF_random, // #7 float() random
3581 PF_sound, // #8 void(entity e, float chan, string samp) sound
3582 PF_normalize, // #9 vector(vector v) normalize
3583 PF_error, // #10 void(string e) error
3584 PF_objerror, // #11 void(string e) objerror
3585 PF_vlen, // #12 float(vector v) vlen
3586 PF_vectoyaw, // #13 float(vector v) vectoyaw
3587 PF_Spawn, // #14 entity() spawn
3588 PF_Remove, // #15 void(entity e) remove
3589 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3590 PF_checkclient, // #17 entity() clientlist
3591 PF_Find, // #18 entity(entity start, .string fld, string match) find
3592 PF_precache_sound, // #19 void(string s) precache_sound
3593 PF_precache_model, // #20 void(string s) precache_model
3594 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3595 PF_findradius, // #22 entity(vector org, float rad) findradius
3596 PF_bprint, // #23 void(string s) bprint
3597 PF_sprint, // #24 void(entity client, string s) sprint
3598 PF_dprint, // #25 void(string s) dprint
3599 PF_ftos, // #26 void(string s) ftos
3600 PF_vtos, // #27 void(string s) vtos
3601 PF_coredump, // #28 void() coredump
3602 PF_traceon, // #29 void() traceon
3603 PF_traceoff, // #30 void() traceoff
3604 PF_eprint, // #31 void(entity e) eprint
3605 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3607 PF_droptofloor, // #34 float() droptofloor
3608 PF_lightstyle, // #35 void(float style, string value) lightstyle
3609 PF_rint, // #36 float(float v) rint
3610 PF_floor, // #37 float(float v) floor
3611 PF_ceil, // #38 float(float v) ceil
3613 PF_checkbottom, // #40 float(entity e) checkbottom
3614 PF_pointcontents, // #41 float(vector v) pointcontents
3616 PF_fabs, // #43 float(float f) fabs
3617 PF_aim, // #44 vector(entity e, float speed) aim
3618 PF_cvar, // #45 float(string s) cvar
3619 PF_localcmd, // #46 void(string s) localcmd
3620 PF_nextent, // #47 entity(entity e) nextent
3621 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3622 PF_changeyaw, // #49 void() ChangeYaw
3624 PF_vectoangles, // #51 vector(vector v) vectoangles
3625 PF_WriteByte, // #52 void(float to, float f) WriteByte
3626 PF_WriteChar, // #53 void(float to, float f) WriteChar
3627 PF_WriteShort, // #54 void(float to, float f) WriteShort
3628 PF_WriteLong, // #55 void(float to, float f) WriteLong
3629 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3630 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3631 PF_WriteString, // #58 void(float to, string s) WriteString
3632 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3633 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3634 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3635 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3636 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3637 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3638 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3640 SV_MoveToGoal, // #67 void(float step) movetogoal
3641 PF_precache_file, // #68 string(string s) precache_file
3642 PF_makestatic, // #69 void(entity e) makestatic
3643 PF_changelevel, // #70 void(string s) changelevel
3645 PF_cvar_set, // #72 void(string var, string val) cvar_set
3646 PF_centerprint, // #73 void(entity client, strings) centerprint
3647 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3648 PF_precache_model, // #75 string(string s) precache_model2
3649 PF_precache_sound, // #76 string(string s) precache_sound2
3650 PF_precache_file, // #77 string(string s) precache_file2
3651 PF_setspawnparms, // #78 void(entity e) setspawnparms
3654 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3663 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3664 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3665 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3666 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3667 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3668 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3669 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3670 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3671 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3672 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3683 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3684 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3685 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3686 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3687 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3688 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3689 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3690 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3691 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3692 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3693 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3694 a a a a a a a a // #120-199
3695 a a a a a a a a a a // #200-299
3696 a a a a a a a a a a // #300-399
3697 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3698 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3699 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3700 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3701 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3702 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3703 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3704 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3705 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3706 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3707 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3708 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3709 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3710 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3711 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3712 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3713 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3714 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3715 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3716 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3717 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3718 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3719 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3720 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3721 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3722 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3723 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3724 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3725 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3726 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3727 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3728 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3729 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3730 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3731 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3732 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3733 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3734 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3735 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3736 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3737 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3738 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3739 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3740 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3741 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3742 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3743 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3744 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3745 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3746 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3747 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3748 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3749 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3750 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3757 a a a a // #460-499 (LordHavoc)
3760 builtin_t *pr_builtins = pr_builtin;
3761 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3763 void PR_Cmd_Init(void)
3765 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3770 void PR_Cmd_Reset(void)
3772 Mem_EmptyPool(pr_strings_mempool);
3774 PR_Files_CloseAll();