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 =
89 "DP_ENT_CUSTOMCOLORMAP "
90 "DP_ENT_EXTERIORMODELTOCLIENT "
92 "DP_ENT_LOWPRECISION "
95 "DP_GFX_EXTERNALTEXTURES "
97 "DP_GFX_QUAKE3MODELTAGS "
101 "DP_HALFLIFE_MAP_CVAR "
106 "DP_MOVETYPEBOUNCEMISSILE "
113 "DP_QC_FINDCHAINFLAGS "
114 "DP_QC_FINDCHAINFLOAT "
117 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
122 "DP_QC_MULTIPLETEMPSTRINGS "
124 "DP_QC_SINCOSSQRTPOW "
127 "DP_QC_TRACE_MOVETYPE_HITMODEL "
128 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
129 "DP_QC_VECTORVECTORS "
133 "DP_SND_DIRECTIONLESSATTNNONE "
140 "DP_SV_CLIENTCOLORS "
142 "DP_SV_DRAWONLYTOCLIENT "
145 "DP_SV_NODRAWTOCLIENT "
147 "DP_SV_PLAYERPHYSICS "
149 "DP_SV_ROTATINGBMODEL "
155 "DP_TE_EXPLOSIONRGB "
157 "DP_TE_PARTICLECUBE "
158 "DP_TE_PARTICLERAIN "
159 "DP_TE_PARTICLESNOW "
161 "DP_TE_QUADEFFECTS1 "
164 "DP_TE_STANDARDEFFECTBUILTINS "
167 "KRIMZON_SV_PARSECLIENTCOMMAND "
171 "PRYDON_CLIENTCURSOR "
172 "TENEBRAE_GFX_DLIGHTS "
174 "NEXUIZ_PLAYERMODEL "
178 qboolean checkextension(char *name)
183 for (e = ENGINE_EXTENSIONS;*e;e++)
190 while (*e && *e != ' ')
192 if (e - start == len)
193 if (!strncasecmp(start, name, len))
203 returns true if the extension is supported by the server
205 checkextension(extensionname)
208 void PF_checkextension (void)
210 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
217 This is a TERMINAL error, which will kill off the entire server.
226 char string[STRINGTEMP_LENGTH];
228 PF_VarString(0, string, sizeof(string));
229 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
230 ed = PROG_TO_EDICT(pr_global_struct->self);
233 PF_ERROR("Program error");
240 Dumps out self, then an error message. The program is aborted and self is
241 removed, but the level can continue.
246 void PF_objerror (void)
249 char string[STRINGTEMP_LENGTH];
251 PF_VarString(0, string, sizeof(string));
252 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
253 ed = PROG_TO_EDICT(pr_global_struct->self);
263 Writes new values for v_forward, v_up, and v_right based on angles
267 void PF_makevectors (void)
269 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
276 Writes new values for v_forward, v_up, and v_right based on the given forward vector
277 vectorvectors(vector, vector)
280 void PF_vectorvectors (void)
282 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
283 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
290 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.
292 setorigin (entity, origin)
295 void PF_setorigin (void)
300 e = G_EDICT(OFS_PARM0);
302 PF_WARNING("setorigin: can not modify world entity\n");
304 PF_WARNING("setorigin: can not modify free entity\n");
305 org = G_VECTOR(OFS_PARM1);
306 VectorCopy (org, e->v->origin);
307 SV_LinkEdict (e, false);
311 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
315 for (i=0 ; i<3 ; i++)
317 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
319 // set derived values
320 VectorCopy (min, e->v->mins);
321 VectorCopy (max, e->v->maxs);
322 VectorSubtract (max, min, e->v->size);
324 SV_LinkEdict (e, false);
331 the size box is rotated by the current angle
332 LordHavoc: no it isn't...
334 setsize (entity, minvector, maxvector)
337 void PF_setsize (void)
342 e = G_EDICT(OFS_PARM0);
344 PF_WARNING("setsize: can not modify world entity\n");
346 PF_WARNING("setsize: can not modify free entity\n");
347 min = G_VECTOR(OFS_PARM1);
348 max = G_VECTOR(OFS_PARM2);
349 SetMinMaxSize (e, min, max, false);
357 setmodel(entity, model)
360 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
361 void PF_setmodel (void)
367 e = G_EDICT(OFS_PARM0);
369 PF_WARNING("setmodel: can not modify world entity\n");
371 PF_WARNING("setmodel: can not modify free entity\n");
372 i = SV_ModelIndex(G_STRING(OFS_PARM1), 1);
373 e->v->model = PR_SetString(sv.model_precache[i]);
374 e->v->modelindex = i;
380 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
381 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
383 SetMinMaxSize (e, quakemins, quakemaxs, true);
386 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
393 broadcast print to everyone on server
398 void PF_bprint (void)
400 char string[STRINGTEMP_LENGTH];
401 PF_VarString(0, string, sizeof(string));
402 SV_BroadcastPrint(string);
409 single print to a specific client
411 sprint(clientent, value)
414 void PF_sprint (void)
418 char string[STRINGTEMP_LENGTH];
420 entnum = G_EDICTNUM(OFS_PARM0);
422 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
424 Con_Print("tried to sprint to a non-client\n");
428 client = svs.clients + entnum-1;
429 PF_VarString(1, string, sizeof(string));
430 MSG_WriteChar(&client->message,svc_print);
431 MSG_WriteString(&client->message, string);
439 single print to a specific client
441 centerprint(clientent, value)
444 void PF_centerprint (void)
448 char string[STRINGTEMP_LENGTH];
450 entnum = G_EDICTNUM(OFS_PARM0);
452 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
454 Con_Print("tried to sprint to a non-client\n");
458 client = svs.clients + entnum-1;
459 PF_VarString(1, string, sizeof(string));
460 MSG_WriteChar(&client->message,svc_centerprint);
461 MSG_WriteString(&client->message, string);
469 vector normalize(vector)
472 void PF_normalize (void)
478 value1 = G_VECTOR(OFS_PARM0);
480 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
484 newvalue[0] = newvalue[1] = newvalue[2] = 0;
488 newvalue[0] = value1[0] * new;
489 newvalue[1] = value1[1] * new;
490 newvalue[2] = value1[2] * new;
493 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
508 value1 = G_VECTOR(OFS_PARM0);
510 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
513 G_FLOAT(OFS_RETURN) = new;
520 float vectoyaw(vector)
523 void PF_vectoyaw (void)
528 value1 = G_VECTOR(OFS_PARM0);
530 if (value1[1] == 0 && value1[0] == 0)
534 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
539 G_FLOAT(OFS_RETURN) = yaw;
547 vector vectoangles(vector)
550 void PF_vectoangles (void)
552 double value1[3], forward, yaw, pitch;
554 VectorCopy(G_VECTOR(OFS_PARM0), value1);
556 if (value1[1] == 0 && value1[0] == 0)
566 // LordHavoc: optimized a bit
569 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
573 else if (value1[1] > 0)
578 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
579 pitch = (atan2(value1[2], forward) * 180 / M_PI);
584 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
591 Returns a number from 0<= num < 1
596 void PF_random (void)
598 G_FLOAT(OFS_RETURN) = lhrandom(0, 1);
605 particle(origin, color, count)
608 void PF_particle (void)
614 org = G_VECTOR(OFS_PARM0);
615 dir = G_VECTOR(OFS_PARM1);
616 color = G_FLOAT(OFS_PARM2);
617 count = G_FLOAT(OFS_PARM3);
618 SV_StartParticle (org, dir, color, count);
628 void PF_ambientsound (void)
632 float vol, attenuation;
635 pos = G_VECTOR (OFS_PARM0);
636 samp = G_STRING(OFS_PARM1);
637 vol = G_FLOAT(OFS_PARM2);
638 attenuation = G_FLOAT(OFS_PARM3);
640 // check to see if samp was properly precached
641 soundnum = SV_SoundIndex(samp, 1);
649 // add an svc_spawnambient command to the level signon packet
652 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
654 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
656 MSG_WriteVector(&sv.signon, pos, sv.protocol);
659 MSG_WriteShort (&sv.signon, soundnum);
661 MSG_WriteByte (&sv.signon, soundnum);
663 MSG_WriteByte (&sv.signon, vol*255);
664 MSG_WriteByte (&sv.signon, attenuation*64);
672 Each entity can have eight independant sound sources, like voice,
675 Channel 0 is an auto-allocate channel, the others override anything
676 already running on that entity/channel pair.
678 An attenuation of 0 will play full volume everywhere in the level.
679 Larger attenuations will drop off.
691 entity = G_EDICT(OFS_PARM0);
692 channel = G_FLOAT(OFS_PARM1);
693 sample = G_STRING(OFS_PARM2);
694 volume = G_FLOAT(OFS_PARM3) * 255;
695 attenuation = G_FLOAT(OFS_PARM4);
697 if (volume < 0 || volume > 255)
698 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
700 if (attenuation < 0 || attenuation > 4)
701 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
703 if (channel < 0 || channel > 7)
704 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
706 SV_StartSound (entity, channel, sample, volume, attenuation);
718 PF_ERROR("break: break statement\n");
725 Used for use tracing and shot targeting
726 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
727 if the tryents flag is set.
729 traceline (vector1, vector2, tryents)
732 void PF_traceline (void)
739 pr_xfunction->builtinsprofile += 30;
741 v1 = G_VECTOR(OFS_PARM0);
742 v2 = G_VECTOR(OFS_PARM1);
743 move = G_FLOAT(OFS_PARM2);
744 ent = G_EDICT(OFS_PARM3);
746 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
748 pr_global_struct->trace_allsolid = trace.allsolid;
749 pr_global_struct->trace_startsolid = trace.startsolid;
750 pr_global_struct->trace_fraction = trace.fraction;
751 pr_global_struct->trace_inwater = trace.inwater;
752 pr_global_struct->trace_inopen = trace.inopen;
753 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
754 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
755 pr_global_struct->trace_plane_dist = trace.plane.dist;
757 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
759 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
760 // FIXME: add trace_endcontents
768 Used for use tracing and shot targeting
769 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
770 if the tryents flag is set.
772 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
775 // LordHavoc: added this for my own use, VERY useful, similar to traceline
776 void PF_tracebox (void)
778 float *v1, *v2, *m1, *m2;
783 pr_xfunction->builtinsprofile += 30;
785 v1 = G_VECTOR(OFS_PARM0);
786 m1 = G_VECTOR(OFS_PARM1);
787 m2 = G_VECTOR(OFS_PARM2);
788 v2 = G_VECTOR(OFS_PARM3);
789 move = G_FLOAT(OFS_PARM4);
790 ent = G_EDICT(OFS_PARM5);
792 trace = SV_Move (v1, m1, m2, v2, move, ent);
794 pr_global_struct->trace_allsolid = trace.allsolid;
795 pr_global_struct->trace_startsolid = trace.startsolid;
796 pr_global_struct->trace_fraction = trace.fraction;
797 pr_global_struct->trace_inwater = trace.inwater;
798 pr_global_struct->trace_inopen = trace.inopen;
799 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
800 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
801 pr_global_struct->trace_plane_dist = trace.plane.dist;
803 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
805 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
808 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
809 void PF_TraceToss (void)
815 pr_xfunction->builtinsprofile += 600;
817 ent = G_EDICT(OFS_PARM0);
818 if (ent == sv.edicts)
819 PF_WARNING("tracetoss: can not use world entity\n");
820 ignore = G_EDICT(OFS_PARM1);
822 trace = SV_Trace_Toss (ent, ignore);
824 pr_global_struct->trace_allsolid = trace.allsolid;
825 pr_global_struct->trace_startsolid = trace.startsolid;
826 pr_global_struct->trace_fraction = trace.fraction;
827 pr_global_struct->trace_inwater = trace.inwater;
828 pr_global_struct->trace_inopen = trace.inopen;
829 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
830 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
831 pr_global_struct->trace_plane_dist = trace.plane.dist;
833 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
835 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
843 Returns true if the given entity can move to the given position from it's
844 current position by walking or rolling.
846 scalar checkpos (entity, vector)
849 void PF_checkpos (void)
853 //============================================================================
856 qbyte checkpvs[MAX_MAP_LEAFS/8];
858 int PF_newcheckclient (int check)
864 // cycle to the next one
866 check = bound(1, check, svs.maxclients);
867 if (check == svs.maxclients)
875 pr_xfunction->builtinsprofile++;
877 if (i == svs.maxclients+1)
879 // look up the client's edict
881 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
882 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
884 // found a valid client (possibly the same one again)
888 // get the PVS for the entity
889 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
891 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
892 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
901 Returns a client (or object that has a client enemy) that would be a
904 If there is more than one valid option, they are cycled each frame
906 If (self.origin + self.viewofs) is not in the PVS of the current target,
907 it is not returned at all.
912 int c_invis, c_notvis;
913 void PF_checkclient (void)
918 // find a new check if on a new frame
919 if (sv.time - sv.lastchecktime >= 0.1)
921 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
922 sv.lastchecktime = sv.time;
925 // return check if it might be visible
926 ent = EDICT_NUM(sv.lastcheck);
927 if (ent->e->free || ent->v->health <= 0)
929 RETURN_EDICT(sv.edicts);
933 // if current entity can't possibly see the check entity, return 0
934 self = PROG_TO_EDICT(pr_global_struct->self);
935 VectorAdd(self->v->origin, self->v->view_ofs, view);
936 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
939 RETURN_EDICT(sv.edicts);
943 // might be able to see it
948 //============================================================================
955 Sends text over to the client's execution buffer
957 stuffcmd (clientent, value)
960 void PF_stuffcmd (void)
966 entnum = G_EDICTNUM(OFS_PARM0);
967 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
969 Con_Print("Can't stuffcmd to a non-client\n");
972 str = G_STRING(OFS_PARM1);
975 host_client = svs.clients + entnum-1;
976 Host_ClientCommands ("%s", str);
984 Sends text to server console
989 void PF_localcmd (void)
991 Cbuf_AddText(G_STRING(OFS_PARM0));
1003 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1013 void PF_cvar_set (void)
1015 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1022 Returns a chain of entities that have origins within a spherical area
1024 findradius (origin, radius)
1027 void PF_findradius (void)
1029 edict_t *ent, *chain;
1030 vec_t radius, radius2;
1031 vec3_t org, eorg, mins, maxs;
1034 edict_t *touchedicts[MAX_EDICTS];
1036 chain = (edict_t *)sv.edicts;
1038 VectorCopy(G_VECTOR(OFS_PARM0), org);
1039 radius = G_FLOAT(OFS_PARM1);
1040 radius2 = radius * radius;
1042 mins[0] = org[0] - radius;
1043 mins[1] = org[1] - radius;
1044 mins[2] = org[2] - radius;
1045 maxs[0] = org[0] + radius;
1046 maxs[1] = org[1] + radius;
1047 maxs[2] = org[2] + radius;
1048 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1049 if (numtouchedicts > MAX_EDICTS)
1051 // this never happens
1052 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1053 numtouchedicts = MAX_EDICTS;
1055 for (i = 0;i < numtouchedicts;i++)
1057 ent = touchedicts[i];
1058 pr_xfunction->builtinsprofile++;
1059 // LordHavoc: compare against bounding box rather than center so it
1060 // doesn't miss large objects, and use DotProduct instead of Length
1061 // for a major speedup
1062 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1063 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1064 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1065 if (DotProduct(eorg, eorg) < radius2)
1067 ent->v->chain = EDICT_TO_PROG(chain);
1072 RETURN_EDICT(chain);
1081 void PF_dprint (void)
1083 char string[STRINGTEMP_LENGTH];
1084 if (developer.integer)
1086 PF_VarString(0, string, sizeof(string));
1095 v = G_FLOAT(OFS_PARM0);
1097 s = PR_GetTempString();
1098 if ((float)((int)v) == v)
1099 sprintf(s, "%i", (int)v);
1101 sprintf(s, "%f", v);
1102 G_INT(OFS_RETURN) = PR_SetString(s);
1108 v = G_FLOAT(OFS_PARM0);
1109 G_FLOAT(OFS_RETURN) = fabs(v);
1115 s = PR_GetTempString();
1116 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1117 G_INT(OFS_RETURN) = PR_SetString(s);
1123 s = PR_GetTempString();
1124 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1125 G_INT(OFS_RETURN) = PR_SetString(s);
1128 void PF_Spawn (void)
1131 pr_xfunction->builtinsprofile += 20;
1136 void PF_Remove (void)
1139 pr_xfunction->builtinsprofile += 20;
1141 ed = G_EDICT(OFS_PARM0);
1142 if (ed == sv.edicts)
1143 PF_WARNING("remove: tried to remove world\n");
1144 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1145 PF_WARNING("remove: tried to remove a client\n");
1146 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1147 if (ed->e->free && developer.integer)
1148 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1153 // entity (entity start, .string field, string match) find = #5;
1161 e = G_EDICTNUM(OFS_PARM0);
1162 f = G_INT(OFS_PARM1);
1163 s = G_STRING(OFS_PARM2);
1166 RETURN_EDICT(sv.edicts);
1170 for (e++ ; e < sv.num_edicts ; e++)
1172 pr_xfunction->builtinsprofile++;
1186 RETURN_EDICT(sv.edicts);
1189 // LordHavoc: added this for searching float, int, and entity reference fields
1190 void PF_FindFloat (void)
1197 e = G_EDICTNUM(OFS_PARM0);
1198 f = G_INT(OFS_PARM1);
1199 s = G_FLOAT(OFS_PARM2);
1201 for (e++ ; e < sv.num_edicts ; e++)
1203 pr_xfunction->builtinsprofile++;
1207 if (E_FLOAT(ed,f) == s)
1214 RETURN_EDICT(sv.edicts);
1217 // chained search for strings in entity fields
1218 // entity(.string field, string match) findchain = #402;
1219 void PF_findchain (void)
1224 edict_t *ent, *chain;
1226 chain = (edict_t *)sv.edicts;
1228 f = G_INT(OFS_PARM0);
1229 s = G_STRING(OFS_PARM1);
1232 RETURN_EDICT(sv.edicts);
1236 ent = NEXT_EDICT(sv.edicts);
1237 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1239 pr_xfunction->builtinsprofile++;
1242 t = E_STRING(ent,f);
1248 ent->v->chain = EDICT_TO_PROG(chain);
1252 RETURN_EDICT(chain);
1255 // LordHavoc: chained search for float, int, and entity reference fields
1256 // entity(.string field, float match) findchainfloat = #403;
1257 void PF_findchainfloat (void)
1262 edict_t *ent, *chain;
1264 chain = (edict_t *)sv.edicts;
1266 f = G_INT(OFS_PARM0);
1267 s = G_FLOAT(OFS_PARM1);
1269 ent = NEXT_EDICT(sv.edicts);
1270 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1272 pr_xfunction->builtinsprofile++;
1275 if (E_FLOAT(ent,f) != s)
1278 ent->v->chain = EDICT_TO_PROG(chain);
1282 RETURN_EDICT(chain);
1285 // LordHavoc: search for flags in float fields
1286 void PF_findflags (void)
1293 e = G_EDICTNUM(OFS_PARM0);
1294 f = G_INT(OFS_PARM1);
1295 s = (int)G_FLOAT(OFS_PARM2);
1297 for (e++ ; e < sv.num_edicts ; e++)
1299 pr_xfunction->builtinsprofile++;
1303 if ((int)E_FLOAT(ed,f) & s)
1310 RETURN_EDICT(sv.edicts);
1313 // LordHavoc: chained search for flags in float fields
1314 void PF_findchainflags (void)
1319 edict_t *ent, *chain;
1321 chain = (edict_t *)sv.edicts;
1323 f = G_INT(OFS_PARM0);
1324 s = (int)G_FLOAT(OFS_PARM1);
1326 ent = NEXT_EDICT(sv.edicts);
1327 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1329 pr_xfunction->builtinsprofile++;
1332 if (!((int)E_FLOAT(ent,f) & s))
1335 ent->v->chain = EDICT_TO_PROG(chain);
1339 RETURN_EDICT(chain);
1342 void PR_CheckEmptyString (char *s)
1345 PF_ERROR("Bad string");
1348 void PF_precache_file (void)
1349 { // precache_file is only used to copy files with qcc, it does nothing
1350 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1354 void PF_precache_sound (void)
1356 SV_SoundIndex(G_STRING(OFS_PARM0), 2);
1357 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1360 void PF_precache_model (void)
1362 SV_ModelIndex(G_STRING(OFS_PARM0), 2);
1363 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1367 void PF_coredump (void)
1372 void PF_traceon (void)
1377 void PF_traceoff (void)
1382 void PF_eprint (void)
1384 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1391 float(float yaw, float dist) walkmove
1394 void PF_walkmove (void)
1402 // assume failure if it returns early
1403 G_FLOAT(OFS_RETURN) = 0;
1405 ent = PROG_TO_EDICT(pr_global_struct->self);
1406 if (ent == sv.edicts)
1407 PF_WARNING("walkmove: can not modify world entity\n");
1409 PF_WARNING("walkmove: can not modify free entity\n");
1410 yaw = G_FLOAT(OFS_PARM0);
1411 dist = G_FLOAT(OFS_PARM1);
1413 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1416 yaw = yaw*M_PI*2 / 360;
1418 move[0] = cos(yaw)*dist;
1419 move[1] = sin(yaw)*dist;
1422 // save program state, because SV_movestep may call other progs
1423 oldf = pr_xfunction;
1424 oldself = pr_global_struct->self;
1426 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1429 // restore program state
1430 pr_xfunction = oldf;
1431 pr_global_struct->self = oldself;
1441 void PF_droptofloor (void)
1447 // assume failure if it returns early
1448 G_FLOAT(OFS_RETURN) = 0;
1450 ent = PROG_TO_EDICT(pr_global_struct->self);
1451 if (ent == sv.edicts)
1452 PF_WARNING("droptofloor: can not modify world entity\n");
1454 PF_WARNING("droptofloor: can not modify free entity\n");
1456 VectorCopy (ent->v->origin, end);
1459 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1461 if (trace.fraction != 1)
1463 VectorCopy (trace.endpos, ent->v->origin);
1464 SV_LinkEdict (ent, false);
1465 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1466 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1467 G_FLOAT(OFS_RETURN) = 1;
1468 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1469 ent->e->suspendedinairflag = true;
1477 void(float style, string value) lightstyle
1480 void PF_lightstyle (void)
1487 style = G_FLOAT(OFS_PARM0);
1488 val = G_STRING(OFS_PARM1);
1490 // change the string in sv
1491 sv.lightstyles[style] = val;
1493 // send message to all clients on this server
1494 if (sv.state != ss_active)
1497 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1501 MSG_WriteChar (&client->message, svc_lightstyle);
1502 MSG_WriteChar (&client->message,style);
1503 MSG_WriteString (&client->message, val);
1511 f = G_FLOAT(OFS_PARM0);
1513 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1515 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1517 void PF_floor (void)
1519 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1523 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1532 void PF_checkbottom (void)
1534 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1542 void PF_pointcontents (void)
1544 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1551 entity nextent(entity)
1554 void PF_nextent (void)
1559 i = G_EDICTNUM(OFS_PARM0);
1562 pr_xfunction->builtinsprofile++;
1564 if (i == sv.num_edicts)
1566 RETURN_EDICT(sv.edicts);
1582 Pick a vector for the player to shoot along
1583 vector aim(entity, missilespeed)
1588 edict_t *ent, *check, *bestent;
1589 vec3_t start, dir, end, bestdir;
1592 float dist, bestdist;
1595 // assume failure if it returns early
1596 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1597 // if sv_aim is so high it can't possibly accept anything, skip out early
1598 if (sv_aim.value >= 1)
1601 ent = G_EDICT(OFS_PARM0);
1602 if (ent == sv.edicts)
1603 PF_WARNING("aim: can not use world entity\n");
1605 PF_WARNING("aim: can not use free entity\n");
1606 speed = G_FLOAT(OFS_PARM1);
1608 VectorCopy (ent->v->origin, start);
1611 // try sending a trace straight
1612 VectorCopy (pr_global_struct->v_forward, dir);
1613 VectorMA (start, 2048, dir, end);
1614 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1615 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1616 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1618 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1623 // try all possible entities
1624 VectorCopy (dir, bestdir);
1625 bestdist = sv_aim.value;
1628 check = NEXT_EDICT(sv.edicts);
1629 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1631 pr_xfunction->builtinsprofile++;
1632 if (check->v->takedamage != DAMAGE_AIM)
1636 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1637 continue; // don't aim at teammate
1638 for (j=0 ; j<3 ; j++)
1639 end[j] = check->v->origin[j]
1640 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1641 VectorSubtract (end, start, dir);
1642 VectorNormalize (dir);
1643 dist = DotProduct (dir, pr_global_struct->v_forward);
1644 if (dist < bestdist)
1645 continue; // to far to turn
1646 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1647 if (tr.ent == check)
1648 { // can shoot at this one
1656 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1657 dist = DotProduct (dir, pr_global_struct->v_forward);
1658 VectorScale (pr_global_struct->v_forward, dist, end);
1660 VectorNormalize (end);
1661 VectorCopy (end, G_VECTOR(OFS_RETURN));
1665 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1673 This was a major timewaster in progs, so it was converted to C
1676 void PF_changeyaw (void)
1679 float ideal, current, move, speed;
1681 ent = PROG_TO_EDICT(pr_global_struct->self);
1682 if (ent == sv.edicts)
1683 PF_WARNING("changeyaw: can not modify world entity\n");
1685 PF_WARNING("changeyaw: can not modify free entity\n");
1686 current = ANGLEMOD(ent->v->angles[1]);
1687 ideal = ent->v->ideal_yaw;
1688 speed = ent->v->yaw_speed;
1690 if (current == ideal)
1692 move = ideal - current;
1693 if (ideal > current)
1714 ent->v->angles[1] = ANGLEMOD (current + move);
1722 void PF_changepitch (void)
1725 float ideal, current, move, speed;
1728 ent = G_EDICT(OFS_PARM0);
1729 if (ent == sv.edicts)
1730 PF_WARNING("changepitch: can not modify world entity\n");
1732 PF_WARNING("changepitch: can not modify free entity\n");
1733 current = ANGLEMOD( ent->v->angles[0] );
1734 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1735 ideal = val->_float;
1738 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1741 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1742 speed = val->_float;
1745 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1749 if (current == ideal)
1751 move = ideal - current;
1752 if (ideal > current)
1773 ent->v->angles[0] = ANGLEMOD (current + move);
1777 ===============================================================================
1781 ===============================================================================
1784 #define MSG_BROADCAST 0 // unreliable to all
1785 #define MSG_ONE 1 // reliable to one (msg_entity)
1786 #define MSG_ALL 2 // reliable to all
1787 #define MSG_INIT 3 // write to the init string
1789 sizebuf_t *WriteDest (void)
1795 dest = G_FLOAT(OFS_PARM0);
1799 return &sv.datagram;
1802 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1803 entnum = NUM_FOR_EDICT(ent);
1804 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1805 Host_Error("WriteDest: tried to write to non-client\n");
1806 return &svs.clients[entnum-1].message;
1809 return &sv.reliable_datagram;
1815 Host_Error("WriteDest: bad destination");
1822 void PF_WriteByte (void)
1824 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1827 void PF_WriteChar (void)
1829 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1832 void PF_WriteShort (void)
1834 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1837 void PF_WriteLong (void)
1839 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1842 void PF_WriteAngle (void)
1844 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1847 void PF_WriteCoord (void)
1849 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1852 void PF_WriteString (void)
1854 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1858 void PF_WriteEntity (void)
1860 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1863 //=============================================================================
1865 void PF_makestatic (void)
1870 ent = G_EDICT(OFS_PARM0);
1871 if (ent == sv.edicts)
1872 PF_WARNING("makestatic: can not modify world entity\n");
1874 PF_WARNING("makestatic: can not modify free entity\n");
1877 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1882 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1883 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1884 MSG_WriteShort (&sv.signon, ent->v->frame);
1888 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1889 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1890 MSG_WriteByte (&sv.signon, ent->v->frame);
1893 MSG_WriteByte (&sv.signon, ent->v->colormap);
1894 MSG_WriteByte (&sv.signon, ent->v->skin);
1895 for (i=0 ; i<3 ; i++)
1897 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1898 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1901 // throw the entity away now
1905 //=============================================================================
1912 void PF_setspawnparms (void)
1918 ent = G_EDICT(OFS_PARM0);
1919 i = NUM_FOR_EDICT(ent);
1920 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1922 Con_Print("tried to setspawnparms on a non-client\n");
1926 // copy spawn parms out of the client_t
1927 client = svs.clients + i-1;
1928 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1929 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1937 void PF_changelevel (void)
1941 // make sure we don't issue two changelevels
1942 if (svs.changelevel_issued)
1944 svs.changelevel_issued = true;
1946 s = G_STRING(OFS_PARM0);
1947 Cbuf_AddText (va("changelevel %s\n",s));
1952 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1957 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1962 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1969 Returns a vector of length < 1
1974 void PF_randomvec (void)
1979 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1980 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1981 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1983 while (DotProduct(temp, temp) >= 1);
1984 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1991 Returns a color vector indicating the lighting at the requested point.
1993 (Internal Operation note: actually measures the light beneath the point, just like
1994 the model lighting on the client)
1999 void PF_GetLight (void)
2001 vec3_t ambientcolor, diffusecolor, diffusenormal;
2003 p = G_VECTOR(OFS_PARM0);
2004 VectorClear(ambientcolor);
2005 VectorClear(diffusecolor);
2006 VectorClear(diffusenormal);
2007 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2008 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2009 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2012 void PF_registercvar (void)
2015 name = G_STRING(OFS_PARM0);
2016 value = G_STRING(OFS_PARM1);
2017 G_FLOAT(OFS_RETURN) = 0;
2019 // first check to see if it has already been defined
2020 if (Cvar_FindVar (name))
2023 // check for overlap with a command
2024 if (Cmd_Exists (name))
2026 Con_Printf("PF_registercvar: %s is a command\n", name);
2030 Cvar_Get(name, value, 0);
2032 G_FLOAT(OFS_RETURN) = 1; // success
2039 returns the minimum of two supplied floats
2046 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2048 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2049 else if (pr_argc >= 3)
2052 float f = G_FLOAT(OFS_PARM0);
2053 for (i = 1;i < pr_argc;i++)
2054 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2055 f = G_FLOAT((OFS_PARM0+i*3));
2056 G_FLOAT(OFS_RETURN) = f;
2060 G_FLOAT(OFS_RETURN) = 0;
2061 PF_WARNING("min: must supply at least 2 floats\n");
2069 returns the maximum of two supplied floats
2076 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2078 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2079 else if (pr_argc >= 3)
2082 float f = G_FLOAT(OFS_PARM0);
2083 for (i = 1;i < pr_argc;i++)
2084 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2085 f = G_FLOAT((OFS_PARM0+i*3));
2086 G_FLOAT(OFS_RETURN) = f;
2090 G_FLOAT(OFS_RETURN) = 0;
2091 PF_WARNING("max: must supply at least 2 floats\n");
2099 returns number bounded by supplied range
2101 min(min, value, max)
2104 void PF_bound (void)
2106 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2113 returns a raised to power b
2120 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2127 copies data from one entity to another
2129 copyentity(src, dst)
2132 void PF_copyentity (void)
2135 in = G_EDICT(OFS_PARM0);
2136 if (in == sv.edicts)
2137 PF_WARNING("copyentity: can not read world entity\n");
2139 PF_WARNING("copyentity: can not read free entity\n");
2140 out = G_EDICT(OFS_PARM1);
2141 if (out == sv.edicts)
2142 PF_WARNING("copyentity: can not modify world entity\n");
2144 PF_WARNING("copyentity: can not modify free entity\n");
2145 memcpy(out->v, in->v, progs->entityfields * 4);
2152 sets the color of a client and broadcasts the update to all connected clients
2154 setcolor(clientent, value)
2157 void PF_setcolor (void)
2163 entnum = G_EDICTNUM(OFS_PARM0);
2164 i = G_FLOAT(OFS_PARM1);
2166 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2168 Con_Print("tried to setcolor a non-client\n");
2172 client = svs.clients + entnum-1;
2175 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2177 client->edict->v->team = (i & 15) + 1;
2180 if (client->old_colors != client->colors)
2182 client->old_colors = client->colors;
2183 // send notification to all clients
2184 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2185 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2186 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2194 effect(origin, modelname, startframe, framecount, framerate)
2197 void PF_effect (void)
2201 s = G_STRING(OFS_PARM1);
2203 PF_WARNING("effect: no model specified\n");
2205 i = SV_ModelIndex(s, 1);
2207 PF_WARNING("effect: model not precached\n");
2208 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2211 void PF_te_blood (void)
2213 if (G_FLOAT(OFS_PARM2) < 1)
2215 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2216 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2218 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2220 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2222 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2223 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2224 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2226 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2229 void PF_te_bloodshower (void)
2231 if (G_FLOAT(OFS_PARM3) < 1)
2233 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2234 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2236 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2237 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2238 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2240 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2244 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2246 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2249 void PF_te_explosionrgb (void)
2251 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2252 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2254 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2255 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2256 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2258 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2259 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2260 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2263 void PF_te_particlecube (void)
2265 if (G_FLOAT(OFS_PARM3) < 1)
2267 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2268 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
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_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2275 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2276 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2278 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2279 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2280 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2282 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2284 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2285 // gravity true/false
2286 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2288 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2291 void PF_te_particlerain (void)
2293 if (G_FLOAT(OFS_PARM3) < 1)
2295 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2296 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2298 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2299 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2300 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2302 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2310 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2312 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2315 void PF_te_particlesnow (void)
2317 if (G_FLOAT(OFS_PARM3) < 1)
2319 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2320 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
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));
2339 void PF_te_spark (void)
2341 if (G_FLOAT(OFS_PARM2) < 1)
2343 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2344 MSG_WriteByte(&sv.datagram, TE_SPARK);
2346 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2347 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2348 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2350 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2351 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2352 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2354 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2357 void PF_te_gunshotquad (void)
2359 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2360 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2362 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2363 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2364 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2367 void PF_te_spikequad (void)
2369 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2370 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2372 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2373 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2374 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2377 void PF_te_superspikequad (void)
2379 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2380 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2382 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2383 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2384 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2387 void PF_te_explosionquad (void)
2389 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2390 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2392 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2393 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2394 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2397 void PF_te_smallflash (void)
2399 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2400 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2402 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2403 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2404 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2407 void PF_te_customflash (void)
2409 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2411 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2412 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
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);
2418 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2420 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2422 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2423 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2424 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2427 void PF_te_gunshot (void)
2429 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2430 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2432 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2433 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2434 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2437 void PF_te_spike (void)
2439 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2440 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2442 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2443 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2444 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2447 void PF_te_superspike (void)
2449 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2450 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2452 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2453 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2454 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2457 void PF_te_explosion (void)
2459 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2462 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2463 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2464 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2467 void PF_te_tarexplosion (void)
2469 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2470 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2472 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2473 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2474 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2477 void PF_te_wizspike (void)
2479 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2480 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2482 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2483 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2484 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2487 void PF_te_knightspike (void)
2489 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2490 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2492 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2493 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2494 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2497 void PF_te_lavasplash (void)
2499 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2500 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2502 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2503 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2504 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2507 void PF_te_teleport (void)
2509 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2510 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2512 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2513 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2514 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2517 void PF_te_explosion2 (void)
2519 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2520 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2522 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2523 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2524 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2526 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2527 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2530 void PF_te_lightning1 (void)
2532 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2533 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2535 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2537 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2538 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2539 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2541 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2542 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2543 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2546 void PF_te_lightning2 (void)
2548 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2549 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2551 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2553 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2554 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2555 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2557 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2558 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2559 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2562 void PF_te_lightning3 (void)
2564 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2565 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2567 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2569 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2570 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2571 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2573 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2574 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2575 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2578 void PF_te_beam (void)
2580 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2581 MSG_WriteByte(&sv.datagram, TE_BEAM);
2583 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2585 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2586 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2587 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2589 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2591 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2594 void PF_te_plasmaburn (void)
2596 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2597 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2598 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2599 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2600 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2603 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2606 vec3_t v1, clipplanenormal, normal;
2607 vec_t clipplanedist, clipdist;
2609 if (surf->flags & SURF_PLANEBACK)
2610 VectorNegate(surf->plane->normal, normal);
2612 VectorCopy(surf->plane->normal, normal);
2613 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2615 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2616 VectorNormalizeFast(v1);
2617 CrossProduct(v1, normal, clipplanenormal);
2618 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2619 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2622 clipdist = -clipdist;
2623 VectorMA(out, clipdist, clipplanenormal, out);
2628 static msurface_t *getsurface(edict_t *ed, int surfnum)
2632 if (!ed || ed->e->free)
2634 modelindex = ed->v->modelindex;
2635 if (modelindex < 1 || modelindex >= MAX_MODELS)
2637 model = sv.models[modelindex];
2638 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2640 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2644 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2645 void PF_getsurfacenumpoints(void)
2648 // return 0 if no such surface
2649 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2651 G_FLOAT(OFS_RETURN) = 0;
2655 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2657 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2658 void PF_getsurfacepoint(void)
2663 VectorClear(G_VECTOR(OFS_RETURN));
2664 ed = G_EDICT(OFS_PARM0);
2665 if (!ed || ed->e->free)
2667 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2669 pointnum = G_FLOAT(OFS_PARM2);
2670 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2672 // FIXME: implement rotation/scaling
2673 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2675 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2676 void PF_getsurfacenormal(void)
2679 VectorClear(G_VECTOR(OFS_RETURN));
2680 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2682 // FIXME: implement rotation/scaling
2683 if (surf->flags & SURF_PLANEBACK)
2684 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2686 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2688 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2689 void PF_getsurfacetexture(void)
2692 G_INT(OFS_RETURN) = 0;
2693 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2695 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2697 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2698 void PF_getsurfacenearpoint(void)
2700 int surfnum, best, modelindex;
2702 vec_t dist, bestdist;
2707 G_FLOAT(OFS_RETURN) = -1;
2708 ed = G_EDICT(OFS_PARM0);
2709 point = G_VECTOR(OFS_PARM1);
2711 if (!ed || ed->e->free)
2713 modelindex = ed->v->modelindex;
2714 if (modelindex < 1 || modelindex >= MAX_MODELS)
2716 model = sv.models[modelindex];
2717 if (!model->brushq1.numsurfaces)
2720 // FIXME: implement rotation/scaling
2721 VectorSubtract(point, ed->v->origin, p);
2723 bestdist = 1000000000;
2724 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2726 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2727 dist = PlaneDiff(p, surf->plane);
2729 if (dist < bestdist)
2731 clippointtosurface(surf, p, clipped);
2732 VectorSubtract(clipped, p, clipped);
2733 dist += DotProduct(clipped, clipped);
2734 if (dist < bestdist)
2741 G_FLOAT(OFS_RETURN) = best;
2743 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2744 void PF_getsurfaceclippedpoint(void)
2749 VectorClear(G_VECTOR(OFS_RETURN));
2750 ed = G_EDICT(OFS_PARM0);
2751 if (!ed || ed->e->free)
2753 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2755 // FIXME: implement rotation/scaling
2756 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2757 clippointtosurface(surf, p, out);
2758 // FIXME: implement rotation/scaling
2759 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2762 #define MAX_PRFILES 256
2764 qfile_t *pr_files[MAX_PRFILES];
2766 void PR_Files_Init(void)
2768 memset(pr_files, 0, sizeof(pr_files));
2771 void PR_Files_CloseAll(void)
2774 for (i = 0;i < MAX_PRFILES;i++)
2777 FS_Close(pr_files[i]);
2782 //float(string s) stof = #81; // get numerical value from a string
2785 char string[STRINGTEMP_LENGTH];
2786 PF_VarString(0, string, sizeof(string));
2787 G_FLOAT(OFS_RETURN) = atof(string);
2790 //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
2794 char *modestring, *filename;
2795 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2796 if (pr_files[filenum] == NULL)
2798 if (filenum >= MAX_PRFILES)
2800 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2801 G_FLOAT(OFS_RETURN) = -2;
2804 mode = G_FLOAT(OFS_PARM1);
2807 case 0: // FILE_READ
2810 case 1: // FILE_APPEND
2813 case 2: // FILE_WRITE
2817 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2818 G_FLOAT(OFS_RETURN) = -3;
2821 filename = G_STRING(OFS_PARM0);
2822 // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2823 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2825 if (pr_files[filenum] == NULL && modestring == "rb")
2826 pr_files[filenum] = FS_Open(filename, modestring, false);
2828 if (pr_files[filenum] == NULL)
2829 G_FLOAT(OFS_RETURN) = -1;
2831 G_FLOAT(OFS_RETURN) = filenum;
2834 //void(float fhandle) fclose = #111; // closes a file
2835 void PF_fclose(void)
2837 int filenum = G_FLOAT(OFS_PARM0);
2838 if (filenum < 0 || filenum >= MAX_PRFILES)
2840 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2843 if (pr_files[filenum] == NULL)
2845 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2848 FS_Close(pr_files[filenum]);
2849 pr_files[filenum] = NULL;
2852 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2856 static char string[STRINGTEMP_LENGTH];
2857 int filenum = G_FLOAT(OFS_PARM0);
2858 if (filenum < 0 || filenum >= MAX_PRFILES)
2860 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2863 if (pr_files[filenum] == NULL)
2865 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2871 c = FS_Getc(pr_files[filenum]);
2872 if (c == '\r' || c == '\n' || c < 0)
2874 if (end < STRINGTEMP_LENGTH - 1)
2878 // remove \n following \r
2881 c = FS_Getc(pr_files[filenum]);
2883 FS_UnGetc(pr_files[filenum], (unsigned char)c);
2885 if (developer.integer)
2886 Con_Printf("fgets: %s\n", string);
2888 G_INT(OFS_RETURN) = PR_SetString(string);
2890 G_INT(OFS_RETURN) = 0;
2893 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2897 char string[STRINGTEMP_LENGTH];
2898 int filenum = G_FLOAT(OFS_PARM0);
2899 if (filenum < 0 || filenum >= MAX_PRFILES)
2901 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2904 if (pr_files[filenum] == NULL)
2906 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2909 PF_VarString(1, string, sizeof(string));
2910 if ((stringlength = strlen(string)))
2911 FS_Write(pr_files[filenum], string, stringlength);
2912 if (developer.integer)
2913 Con_Printf("fputs: %s\n", string);
2916 //float(string s) strlen = #114; // returns how many characters are in a string
2917 void PF_strlen(void)
2920 s = G_STRING(OFS_PARM0);
2922 G_FLOAT(OFS_RETURN) = strlen(s);
2924 G_FLOAT(OFS_RETURN) = 0;
2927 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2928 void PF_strcat(void)
2930 char *s = PR_GetTempString();
2931 PF_VarString(0, s, STRINGTEMP_LENGTH);
2932 G_INT(OFS_RETURN) = PR_SetString(s);
2935 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2936 void PF_substring(void)
2938 int i, start, length;
2939 char *s, *string = PR_GetTempString();
2940 s = G_STRING(OFS_PARM0);
2941 start = G_FLOAT(OFS_PARM1);
2942 length = G_FLOAT(OFS_PARM2);
2945 for (i = 0;i < start && *s;i++, s++);
2946 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2949 G_INT(OFS_RETURN) = PR_SetString(string);
2952 //vector(string s) stov = #117; // returns vector value from a string
2955 char string[STRINGTEMP_LENGTH];
2956 PF_VarString(0, string, sizeof(string));
2957 Math_atov(string, G_VECTOR(OFS_RETURN));
2960 //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)
2961 void PF_strzone(void)
2964 in = G_STRING(OFS_PARM0);
2965 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2967 G_INT(OFS_RETURN) = PR_SetString(out);
2970 //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!!!)
2971 void PF_strunzone(void)
2973 Mem_Free(G_STRING(OFS_PARM0));
2976 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2977 //this function originally written by KrimZon, made shorter by LordHavoc
2978 void PF_clientcommand (void)
2980 client_t *temp_client;
2983 //find client for this entity
2984 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2985 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2987 Con_Print("PF_clientcommand: entity is not a client\n");
2991 temp_client = host_client;
2992 host_client = svs.clients + i;
2993 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
2994 host_client = temp_client;
2997 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2998 //this function originally written by KrimZon, made shorter by LordHavoc
2999 //20040203: rewritten by LordHavoc (no longer uses allocations)
3001 char *tokens[256], tokenbuf[4096];
3002 void PF_tokenize (void)
3006 p = G_STRING(OFS_PARM0);
3010 while(COM_ParseToken(&p, false))
3012 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3014 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3016 tokens[num_tokens++] = tokenbuf + pos;
3017 strcpy(tokenbuf + pos, com_token);
3018 pos += strlen(com_token) + 1;
3021 G_FLOAT(OFS_RETURN) = num_tokens;
3024 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3025 //this function originally written by KrimZon, made shorter by LordHavoc
3028 int token_num = G_FLOAT(OFS_PARM0);
3029 if (token_num >= 0 && token_num < num_tokens)
3030 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3032 G_INT(OFS_RETURN) = PR_SetString("");
3035 //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)
3036 void PF_setattachment (void)
3038 edict_t *e = G_EDICT(OFS_PARM0);
3039 edict_t *tagentity = G_EDICT(OFS_PARM1);
3040 char *tagname = G_STRING(OFS_PARM2);
3046 PF_WARNING("setattachment: can not modify world entity\n");
3048 PF_WARNING("setattachment: can not modify free entity\n");
3050 if (tagentity == NULL)
3051 tagentity = sv.edicts;
3053 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3055 v->edict = EDICT_TO_PROG(tagentity);
3057 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3060 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3062 modelindex = (int)tagentity->v->modelindex;
3063 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3065 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3066 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3067 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3069 // FIXME: use a model function to get tag info (need to handle skeletal)
3070 if (v->_float == 0 && model->alias.aliasnum_tags)
3071 for (i = 0;i < model->alias.aliasnum_tags;i++)
3072 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3075 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);
3078 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));
3082 /////////////////////////////////////////
3083 // DP_MD3_TAGINFO extension coded by VorteX
3085 int SV_GetTagIndex (edict_t *e, char *tagname)
3090 i = e->v->modelindex;
3091 if (i < 1 || i >= MAX_MODELS)
3093 model = sv.models[i];
3096 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3098 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3100 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3109 for (i = 0;i < model->alias.aliasnum_tags; i++)
3111 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3118 return tagindex + 1;
3121 // Warnings/errors code:
3122 // 0 - normal (everything all-right)
3125 // 3 - null or non-precached model
3126 // 4 - no tags with requested index
3127 // 5 - runaway loop at attachment chain
3128 extern cvar_t cl_bob;
3129 extern cvar_t cl_bobcycle;
3130 extern cvar_t cl_bobup;
3131 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3134 int modelindex, reqtag, reqframe, attachloop;
3135 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3139 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3141 if (ent == sv.edicts)
3146 modelindex = (int)ent->v->modelindex;
3147 if (modelindex <= 0 || modelindex > MAX_MODELS)
3150 model = sv.models[modelindex];
3151 reqtag = model->alias.aliasnum_tags;
3153 if (tagindex <= 0 || tagindex > reqtag)
3155 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3160 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3161 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3163 reqframe = ent->v->frame;
3165 // get initial tag matrix
3168 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3169 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3172 Matrix4x4_CreateIdentity(&tagmatrix);
3174 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3175 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3179 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3180 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3181 Matrix4x4_CreateIdentity(&attachmatrix);
3182 if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS)
3184 model = sv.models[(int)attachent->v->modelindex];
3185 if (val->_float < model->alias.aliasnum_tags)
3187 // got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3188 model = sv.models[(int)attachent->v->modelindex];
3189 reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3190 Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3194 // apply transformation by child entity matrix
3195 val = GETEDICTFIELDVALUE(ent, eval_scale);
3196 if (val->_float == 0)
3198 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);
3199 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3200 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]);
3201 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]);
3202 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]);
3203 Matrix4x4_Copy(&tagmatrix, out);
3205 // finally transformate by matrix of tag on parent entity
3206 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3207 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];
3208 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];
3209 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];
3210 Matrix4x4_Copy(&tagmatrix, out);
3214 if (attachloop > 255) // prevent runaway looping
3217 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3220 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3221 val = GETEDICTFIELDVALUE(ent, eval_scale);
3222 if (val->_float == 0)
3224 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3225 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);
3226 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3227 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]);
3228 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]);
3229 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]);
3231 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3232 {// RENDER_VIEWMODEL magic
3233 Matrix4x4_Copy(&tagmatrix, out);
3234 ent = EDICT_NUM(val->edict);
3236 val = GETEDICTFIELDVALUE(ent, eval_scale);
3237 if (val->_float == 0)
3240 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);
3241 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3242 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]);
3243 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]);
3244 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]);
3247 // Cl_bob, ported from rendering code
3248 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3251 // LordHavoc: this code is *weird*, but not replacable (I think it
3252 // should be done in QC on the server, but oh well, quake is quake)
3253 // LordHavoc: figured out bobup: the time at which the sin is at 180
3254 // degrees (which allows lengthening or squishing the peak or valley)
3255 cycle = sv.time/cl_bobcycle.value;
3256 cycle -= (int)cycle;
3257 if (cycle < cl_bobup.value)
3258 cycle = sin(M_PI * cycle / cl_bobup.value);
3260 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3261 // bob is proportional to velocity in the xy plane
3262 // (don't count Z, or jumping messes it up)
3263 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3264 bob = bob*0.3 + bob*0.7*cycle;
3265 out->m[2][3] += bound(-7, bob, 4);
3272 //float(entity ent, string tagname) gettagindex;
3274 void PF_gettagindex (void)
3276 edict_t *ent = G_EDICT(OFS_PARM0);
3277 char *tag_name = G_STRING(OFS_PARM1);
3278 int modelindex, tag_index;
3280 if (ent == sv.edicts)
3281 PF_WARNING("gettagindex: can't affect world entity\n");
3283 PF_WARNING("gettagindex: can't affect free entity\n");
3285 modelindex = (int)ent->v->modelindex;
3287 if (modelindex <= 0 || modelindex > MAX_MODELS)
3288 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3291 tag_index = SV_GetTagIndex(ent, tag_name);
3293 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3295 G_FLOAT(OFS_RETURN) = tag_index;
3298 //vector(entity ent, float tagindex) gettaginfo;
3299 void PF_gettaginfo (void)
3301 edict_t *e = G_EDICT(OFS_PARM0);
3302 int tagindex = (int)G_FLOAT(OFS_PARM1);
3303 matrix4x4_t tag_matrix;
3306 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3307 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3312 PF_WARNING("gettagindex: can't affect world entity\n");
3315 PF_WARNING("gettagindex: can't affect free entity\n");
3318 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3321 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3324 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3330 /////////////////////////////////////////
3331 // DP_QC_FS_SEARCH extension
3333 // qc fs search handling
3334 #define MAX_SEARCHES 128
3336 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3338 void PR_Search_Init(void)
3340 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3343 void PR_Search_Reset(void)
3346 // reset the fssearch list
3347 for(i = 0; i < MAX_SEARCHES; i++)
3348 if(pr_fssearchlist[i])
3349 FS_FreeSearch(pr_fssearchlist[i]);
3350 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3357 float search_begin(string pattern, float caseinsensitive, float quiet)
3360 void PF_search_begin(void)
3364 int caseinsens, quiet;
3366 pattern = G_STRING(OFS_PARM0);
3368 PR_CheckEmptyString(pattern);
3370 caseinsens = G_FLOAT(OFS_PARM1);
3371 quiet = G_FLOAT(OFS_PARM2);
3373 for(handle = 0; handle < MAX_SEARCHES; handle++)
3374 if(!pr_fssearchlist[handle])
3377 if(handle >= MAX_SEARCHES)
3379 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3380 G_FLOAT(OFS_RETURN) = -2;
3384 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3385 G_FLOAT(OFS_RETURN) = -1;
3387 G_FLOAT(OFS_RETURN) = handle;
3394 void search_end(float handle)
3397 void PF_search_end(void)
3401 handle = G_FLOAT(OFS_PARM0);
3403 if(handle < 0 || handle >= MAX_SEARCHES)
3405 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3408 if(pr_fssearchlist[handle] == NULL)
3410 Con_Printf("PF_search_end: no such handle %i\n", handle);
3414 FS_FreeSearch(pr_fssearchlist[handle]);
3415 pr_fssearchlist[handle] = NULL;
3422 float search_getsize(float handle)
3425 void PF_search_getsize(void)
3429 handle = G_FLOAT(OFS_PARM0);
3431 if(handle < 0 || handle >= MAX_SEARCHES)
3433 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3436 if(pr_fssearchlist[handle] == NULL)
3438 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3442 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3447 VM_search_getfilename
3449 string search_getfilename(float handle, float num)
3452 void PF_search_getfilename(void)
3454 int handle, filenum;
3457 handle = G_FLOAT(OFS_PARM0);
3458 filenum = G_FLOAT(OFS_PARM1);
3460 if(handle < 0 || handle >= MAX_SEARCHES)
3462 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3465 if(pr_fssearchlist[handle] == NULL)
3467 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3470 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3472 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3476 tmp = PR_GetTempString();
3477 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3479 G_INT(OFS_RETURN) = PR_SetString(tmp);
3482 void PF_cvar_string (void)
3488 str = G_STRING(OFS_PARM0);
3489 var = Cvar_FindVar (str);
3492 tmp = PR_GetTempString();
3493 strcpy(tmp, var->string);
3497 G_INT(OFS_RETURN) = PR_SetString(tmp);
3500 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3501 void PF_dropclient (void)
3504 client_t *oldhostclient;
3505 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3506 if (clientnum < 0 || clientnum >= svs.maxclients)
3507 PF_WARNING("dropclient: not a client\n");
3508 if (!svs.clients[clientnum].active)
3509 PF_WARNING("dropclient: that client slot is not connected\n");
3510 oldhostclient = host_client;
3511 host_client = svs.clients + clientnum;
3512 SV_DropClient(false);
3513 host_client = oldhostclient;
3516 //entity() spawnclient (DP_SV_BOTCLIENT)
3517 void PF_spawnclient (void)
3521 pr_xfunction->builtinsprofile += 2;
3523 for (i = 0;i < svs.maxclients;i++)
3525 if (!svs.clients[i].active)
3527 pr_xfunction->builtinsprofile += 100;
3528 SV_ConnectClient (i, NULL);
3529 ed = EDICT_NUM(i + 1);
3536 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3537 void PF_clienttype (void)
3540 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3541 if (clientnum < 0 || clientnum >= svs.maxclients)
3542 G_FLOAT(OFS_RETURN) = 3;
3543 else if (!svs.clients[clientnum].active)
3544 G_FLOAT(OFS_RETURN) = 0;
3545 else if (svs.clients[clientnum].netconnection)
3546 G_FLOAT(OFS_RETURN) = 1;
3548 G_FLOAT(OFS_RETURN) = 2;
3551 builtin_t pr_builtin[] =
3554 PF_makevectors, // #1 void(entity e) makevectors
3555 PF_setorigin, // #2 void(entity e, vector o) setorigin
3556 PF_setmodel, // #3 void(entity e, string m) setmodel
3557 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3558 NULL, // #5 void(entity e, vector min, vector max) setabssize
3559 PF_break, // #6 void() break
3560 PF_random, // #7 float() random
3561 PF_sound, // #8 void(entity e, float chan, string samp) sound
3562 PF_normalize, // #9 vector(vector v) normalize
3563 PF_error, // #10 void(string e) error
3564 PF_objerror, // #11 void(string e) objerror
3565 PF_vlen, // #12 float(vector v) vlen
3566 PF_vectoyaw, // #13 float(vector v) vectoyaw
3567 PF_Spawn, // #14 entity() spawn
3568 PF_Remove, // #15 void(entity e) remove
3569 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3570 PF_checkclient, // #17 entity() clientlist
3571 PF_Find, // #18 entity(entity start, .string fld, string match) find
3572 PF_precache_sound, // #19 void(string s) precache_sound
3573 PF_precache_model, // #20 void(string s) precache_model
3574 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3575 PF_findradius, // #22 entity(vector org, float rad) findradius
3576 PF_bprint, // #23 void(string s) bprint
3577 PF_sprint, // #24 void(entity client, string s) sprint
3578 PF_dprint, // #25 void(string s) dprint
3579 PF_ftos, // #26 void(string s) ftos
3580 PF_vtos, // #27 void(string s) vtos
3581 PF_coredump, // #28 void() coredump
3582 PF_traceon, // #29 void() traceon
3583 PF_traceoff, // #30 void() traceoff
3584 PF_eprint, // #31 void(entity e) eprint
3585 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3587 PF_droptofloor, // #34 float() droptofloor
3588 PF_lightstyle, // #35 void(float style, string value) lightstyle
3589 PF_rint, // #36 float(float v) rint
3590 PF_floor, // #37 float(float v) floor
3591 PF_ceil, // #38 float(float v) ceil
3593 PF_checkbottom, // #40 float(entity e) checkbottom
3594 PF_pointcontents, // #41 float(vector v) pointcontents
3596 PF_fabs, // #43 float(float f) fabs
3597 PF_aim, // #44 vector(entity e, float speed) aim
3598 PF_cvar, // #45 float(string s) cvar
3599 PF_localcmd, // #46 void(string s) localcmd
3600 PF_nextent, // #47 entity(entity e) nextent
3601 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3602 PF_changeyaw, // #49 void() ChangeYaw
3604 PF_vectoangles, // #51 vector(vector v) vectoangles
3605 PF_WriteByte, // #52 void(float to, float f) WriteByte
3606 PF_WriteChar, // #53 void(float to, float f) WriteChar
3607 PF_WriteShort, // #54 void(float to, float f) WriteShort
3608 PF_WriteLong, // #55 void(float to, float f) WriteLong
3609 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3610 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3611 PF_WriteString, // #58 void(float to, string s) WriteString
3612 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3613 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3614 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3615 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3616 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3617 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3618 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3620 SV_MoveToGoal, // #67 void(float step) movetogoal
3621 PF_precache_file, // #68 string(string s) precache_file
3622 PF_makestatic, // #69 void(entity e) makestatic
3623 PF_changelevel, // #70 void(string s) changelevel
3625 PF_cvar_set, // #72 void(string var, string val) cvar_set
3626 PF_centerprint, // #73 void(entity client, strings) centerprint
3627 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3628 PF_precache_model, // #75 string(string s) precache_model2
3629 PF_precache_sound, // #76 string(string s) precache_sound2
3630 PF_precache_file, // #77 string(string s) precache_file2
3631 PF_setspawnparms, // #78 void(entity e) setspawnparms
3634 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3643 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3644 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3645 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3646 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3647 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3648 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3649 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3650 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3651 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3652 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3663 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3664 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3665 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3666 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3667 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3668 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3669 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3670 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3671 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3672 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3673 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3674 a a a a a a a a // #120-199
3675 a a a a a a a a a a // #200-299
3676 a a a a a a a a a a // #300-399
3677 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3678 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3679 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3680 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3681 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3682 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3683 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3684 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3685 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3686 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3687 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3688 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3689 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3690 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3691 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3692 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3693 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3694 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3695 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3696 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3697 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3698 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3699 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3700 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3701 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3702 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3703 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3704 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3705 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3706 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3707 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3708 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3709 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3710 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3711 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3712 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3713 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3714 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3715 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3716 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3717 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3718 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3719 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3720 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3721 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3722 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3723 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3724 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3725 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3726 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3727 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3728 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3729 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3730 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3731 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3732 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3737 a a a a // #460-499 (LordHavoc)
3740 builtin_t *pr_builtins = pr_builtin;
3741 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3743 void PR_Cmd_Init(void)
3745 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3750 void PR_Cmd_Shutdown(void)
3752 Mem_FreePool (&pr_strings_mempool);
3755 void PR_Cmd_Reset(void)
3757 Mem_EmptyPool(pr_strings_mempool);
3759 PR_Files_CloseAll();