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 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
27 #define STRINGTEMP_BUFFERS 16
28 #define STRINGTEMP_LENGTH 4096
29 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
30 static int pr_string_tempindex = 0;
32 static char *PR_GetTempString(void)
35 s = pr_string_temp[pr_string_tempindex];
36 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
40 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
41 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
42 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
46 ===============================================================================
50 ===============================================================================
54 void PF_VarString(int first, char *out, int outlength)
60 outend = out + outlength - 1;
61 for (i = first;i < pr_argc && out < outend;i++)
63 s = G_STRING((OFS_PARM0+i*3));
64 while (out < outend && *s)
70 char *ENGINE_EXTENSIONS =
87 "DP_ENT_CUSTOMCOLORMAP "
88 "DP_ENT_EXTERIORMODELTOCLIENT "
90 "DP_ENT_LOWPRECISION "
93 "DP_GFX_EXTERNALTEXTURES "
95 "DP_GFX_QUAKE3MODELTAGS "
99 "DP_HALFLIFE_MAP_CVAR "
100 "DP_HALFLIFE_SPRITE "
105 "DP_MOVETYPEBOUNCEMISSILE "
112 "DP_QC_FINDCHAINFLAGS "
113 "DP_QC_FINDCHAINFLOAT "
116 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
121 "DP_QC_MULTIPLETEMPSTRINGS "
123 "DP_QC_SINCOSSQRTPOW "
126 "DP_QC_TRACE_MOVETYPE_HITMODEL "
127 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
128 "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(const 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_SetEngineString(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 + 1);
1043 mins[1] = org[1] - (radius + 1);
1044 mins[2] = org[2] - (radius + 1);
1045 maxs[0] = org[0] + (radius + 1);
1046 maxs[1] = org[1] + (radius + 1);
1047 maxs[2] = org[2] + (radius + 1);
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 // Quake did not return non-solid entities but darkplaces does
1060 // (note: this is the reason you can't blow up fallen zombies)
1061 if (ent->v->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1063 // LordHavoc: compare against bounding box rather than center so it
1064 // doesn't miss large objects, and use DotProduct instead of Length
1065 // for a major speedup
1066 VectorSubtract(org, ent->v->origin, eorg);
1067 if (sv_gameplayfix_findradiusdistancetobox.integer)
1069 eorg[0] -= bound(ent->v->mins[0], eorg[0], ent->v->maxs[0]);
1070 eorg[1] -= bound(ent->v->mins[1], eorg[1], ent->v->maxs[1]);
1071 eorg[2] -= bound(ent->v->mins[2], eorg[2], ent->v->maxs[2]);
1074 VectorMAMAM(1, eorg, 0.5f, ent->v->mins, 0.5f, ent->v->maxs, eorg);
1075 if (DotProduct(eorg, eorg) < radius2)
1077 ent->v->chain = EDICT_TO_PROG(chain);
1082 RETURN_EDICT(chain);
1091 void PF_dprint (void)
1093 char string[STRINGTEMP_LENGTH];
1094 if (developer.integer)
1096 PF_VarString(0, string, sizeof(string));
1105 v = G_FLOAT(OFS_PARM0);
1107 s = PR_GetTempString();
1108 if ((float)((int)v) == v)
1109 sprintf(s, "%i", (int)v);
1111 sprintf(s, "%f", v);
1112 G_INT(OFS_RETURN) = PR_SetEngineString(s);
1118 v = G_FLOAT(OFS_PARM0);
1119 G_FLOAT(OFS_RETURN) = fabs(v);
1125 s = PR_GetTempString();
1126 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1127 G_INT(OFS_RETURN) = PR_SetEngineString(s);
1133 s = PR_GetTempString();
1134 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1135 G_INT(OFS_RETURN) = PR_SetEngineString(s);
1138 void PF_Spawn (void)
1141 pr_xfunction->builtinsprofile += 20;
1146 void PF_Remove (void)
1149 pr_xfunction->builtinsprofile += 20;
1151 ed = G_EDICT(OFS_PARM0);
1152 if (ed == sv.edicts)
1153 PF_WARNING("remove: tried to remove world\n");
1154 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1155 PF_WARNING("remove: tried to remove a client\n");
1156 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1157 if (ed->e->free && developer.integer)
1158 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1163 // entity (entity start, .string field, string match) find = #5;
1171 e = G_EDICTNUM(OFS_PARM0);
1172 f = G_INT(OFS_PARM1);
1173 s = G_STRING(OFS_PARM2);
1176 RETURN_EDICT(sv.edicts);
1180 for (e++ ; e < sv.num_edicts ; e++)
1182 pr_xfunction->builtinsprofile++;
1196 RETURN_EDICT(sv.edicts);
1199 // LordHavoc: added this for searching float, int, and entity reference fields
1200 void PF_FindFloat (void)
1207 e = G_EDICTNUM(OFS_PARM0);
1208 f = G_INT(OFS_PARM1);
1209 s = G_FLOAT(OFS_PARM2);
1211 for (e++ ; e < sv.num_edicts ; e++)
1213 pr_xfunction->builtinsprofile++;
1217 if (E_FLOAT(ed,f) == s)
1224 RETURN_EDICT(sv.edicts);
1227 // chained search for strings in entity fields
1228 // entity(.string field, string match) findchain = #402;
1229 void PF_findchain (void)
1234 edict_t *ent, *chain;
1236 chain = (edict_t *)sv.edicts;
1238 f = G_INT(OFS_PARM0);
1239 s = G_STRING(OFS_PARM1);
1242 RETURN_EDICT(sv.edicts);
1246 ent = NEXT_EDICT(sv.edicts);
1247 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1249 pr_xfunction->builtinsprofile++;
1252 t = E_STRING(ent,f);
1258 ent->v->chain = EDICT_TO_PROG(chain);
1262 RETURN_EDICT(chain);
1265 // LordHavoc: chained search for float, int, and entity reference fields
1266 // entity(.string field, float match) findchainfloat = #403;
1267 void PF_findchainfloat (void)
1272 edict_t *ent, *chain;
1274 chain = (edict_t *)sv.edicts;
1276 f = G_INT(OFS_PARM0);
1277 s = G_FLOAT(OFS_PARM1);
1279 ent = NEXT_EDICT(sv.edicts);
1280 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1282 pr_xfunction->builtinsprofile++;
1285 if (E_FLOAT(ent,f) != s)
1288 ent->v->chain = EDICT_TO_PROG(chain);
1292 RETURN_EDICT(chain);
1295 // LordHavoc: search for flags in float fields
1296 void PF_findflags (void)
1303 e = G_EDICTNUM(OFS_PARM0);
1304 f = G_INT(OFS_PARM1);
1305 s = (int)G_FLOAT(OFS_PARM2);
1307 for (e++ ; e < sv.num_edicts ; e++)
1309 pr_xfunction->builtinsprofile++;
1313 if ((int)E_FLOAT(ed,f) & s)
1320 RETURN_EDICT(sv.edicts);
1323 // LordHavoc: chained search for flags in float fields
1324 void PF_findchainflags (void)
1329 edict_t *ent, *chain;
1331 chain = (edict_t *)sv.edicts;
1333 f = G_INT(OFS_PARM0);
1334 s = (int)G_FLOAT(OFS_PARM1);
1336 ent = NEXT_EDICT(sv.edicts);
1337 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1339 pr_xfunction->builtinsprofile++;
1342 if (!((int)E_FLOAT(ent,f) & s))
1345 ent->v->chain = EDICT_TO_PROG(chain);
1349 RETURN_EDICT(chain);
1352 void PF_precache_file (void)
1353 { // precache_file is only used to copy files with qcc, it does nothing
1354 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1358 void PF_precache_sound (void)
1360 SV_SoundIndex(G_STRING(OFS_PARM0), 2);
1361 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1364 void PF_precache_model (void)
1366 SV_ModelIndex(G_STRING(OFS_PARM0), 2);
1367 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1371 void PF_coredump (void)
1376 void PF_traceon (void)
1381 void PF_traceoff (void)
1386 void PF_eprint (void)
1388 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1395 float(float yaw, float dist) walkmove
1398 void PF_walkmove (void)
1406 // assume failure if it returns early
1407 G_FLOAT(OFS_RETURN) = 0;
1409 ent = PROG_TO_EDICT(pr_global_struct->self);
1410 if (ent == sv.edicts)
1411 PF_WARNING("walkmove: can not modify world entity\n");
1413 PF_WARNING("walkmove: can not modify free entity\n");
1414 yaw = G_FLOAT(OFS_PARM0);
1415 dist = G_FLOAT(OFS_PARM1);
1417 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1420 yaw = yaw*M_PI*2 / 360;
1422 move[0] = cos(yaw)*dist;
1423 move[1] = sin(yaw)*dist;
1426 // save program state, because SV_movestep may call other progs
1427 oldf = pr_xfunction;
1428 oldself = pr_global_struct->self;
1430 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1433 // restore program state
1434 pr_xfunction = oldf;
1435 pr_global_struct->self = oldself;
1445 void PF_droptofloor (void)
1451 // assume failure if it returns early
1452 G_FLOAT(OFS_RETURN) = 0;
1454 ent = PROG_TO_EDICT(pr_global_struct->self);
1455 if (ent == sv.edicts)
1456 PF_WARNING("droptofloor: can not modify world entity\n");
1458 PF_WARNING("droptofloor: can not modify free entity\n");
1460 VectorCopy (ent->v->origin, end);
1463 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1465 if (trace.fraction != 1)
1467 VectorCopy (trace.endpos, ent->v->origin);
1468 SV_LinkEdict (ent, false);
1469 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1470 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1471 G_FLOAT(OFS_RETURN) = 1;
1472 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1473 ent->e->suspendedinairflag = true;
1481 void(float style, string value) lightstyle
1484 void PF_lightstyle (void)
1491 style = G_FLOAT(OFS_PARM0);
1492 val = G_STRING(OFS_PARM1);
1494 // change the string in sv
1495 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1497 // send message to all clients on this server
1498 if (sv.state != ss_active)
1501 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1505 MSG_WriteChar (&client->message, svc_lightstyle);
1506 MSG_WriteChar (&client->message,style);
1507 MSG_WriteString (&client->message, val);
1515 f = G_FLOAT(OFS_PARM0);
1517 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1519 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1521 void PF_floor (void)
1523 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1527 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1536 void PF_checkbottom (void)
1538 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1546 void PF_pointcontents (void)
1548 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1555 entity nextent(entity)
1558 void PF_nextent (void)
1563 i = G_EDICTNUM(OFS_PARM0);
1566 pr_xfunction->builtinsprofile++;
1568 if (i == sv.num_edicts)
1570 RETURN_EDICT(sv.edicts);
1586 Pick a vector for the player to shoot along
1587 vector aim(entity, missilespeed)
1592 edict_t *ent, *check, *bestent;
1593 vec3_t start, dir, end, bestdir;
1596 float dist, bestdist;
1599 // assume failure if it returns early
1600 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1601 // if sv_aim is so high it can't possibly accept anything, skip out early
1602 if (sv_aim.value >= 1)
1605 ent = G_EDICT(OFS_PARM0);
1606 if (ent == sv.edicts)
1607 PF_WARNING("aim: can not use world entity\n");
1609 PF_WARNING("aim: can not use free entity\n");
1610 speed = G_FLOAT(OFS_PARM1);
1612 VectorCopy (ent->v->origin, start);
1615 // try sending a trace straight
1616 VectorCopy (pr_global_struct->v_forward, dir);
1617 VectorMA (start, 2048, dir, end);
1618 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1619 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1620 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1622 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1627 // try all possible entities
1628 VectorCopy (dir, bestdir);
1629 bestdist = sv_aim.value;
1632 check = NEXT_EDICT(sv.edicts);
1633 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1635 pr_xfunction->builtinsprofile++;
1636 if (check->v->takedamage != DAMAGE_AIM)
1640 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1641 continue; // don't aim at teammate
1642 for (j=0 ; j<3 ; j++)
1643 end[j] = check->v->origin[j]
1644 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1645 VectorSubtract (end, start, dir);
1646 VectorNormalize (dir);
1647 dist = DotProduct (dir, pr_global_struct->v_forward);
1648 if (dist < bestdist)
1649 continue; // to far to turn
1650 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1651 if (tr.ent == check)
1652 { // can shoot at this one
1660 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1661 dist = DotProduct (dir, pr_global_struct->v_forward);
1662 VectorScale (pr_global_struct->v_forward, dist, end);
1664 VectorNormalize (end);
1665 VectorCopy (end, G_VECTOR(OFS_RETURN));
1669 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1677 This was a major timewaster in progs, so it was converted to C
1680 void PF_changeyaw (void)
1683 float ideal, current, move, speed;
1685 ent = PROG_TO_EDICT(pr_global_struct->self);
1686 if (ent == sv.edicts)
1687 PF_WARNING("changeyaw: can not modify world entity\n");
1689 PF_WARNING("changeyaw: can not modify free entity\n");
1690 current = ANGLEMOD(ent->v->angles[1]);
1691 ideal = ent->v->ideal_yaw;
1692 speed = ent->v->yaw_speed;
1694 if (current == ideal)
1696 move = ideal - current;
1697 if (ideal > current)
1718 ent->v->angles[1] = ANGLEMOD (current + move);
1726 void PF_changepitch (void)
1729 float ideal, current, move, speed;
1732 ent = G_EDICT(OFS_PARM0);
1733 if (ent == sv.edicts)
1734 PF_WARNING("changepitch: can not modify world entity\n");
1736 PF_WARNING("changepitch: can not modify free entity\n");
1737 current = ANGLEMOD( ent->v->angles[0] );
1738 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1739 ideal = val->_float;
1742 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1745 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1746 speed = val->_float;
1749 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1753 if (current == ideal)
1755 move = ideal - current;
1756 if (ideal > current)
1777 ent->v->angles[0] = ANGLEMOD (current + move);
1781 ===============================================================================
1785 ===============================================================================
1788 #define MSG_BROADCAST 0 // unreliable to all
1789 #define MSG_ONE 1 // reliable to one (msg_entity)
1790 #define MSG_ALL 2 // reliable to all
1791 #define MSG_INIT 3 // write to the init string
1793 sizebuf_t *WriteDest (void)
1799 dest = G_FLOAT(OFS_PARM0);
1803 return &sv.datagram;
1806 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1807 entnum = NUM_FOR_EDICT(ent);
1808 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1809 Host_Error("WriteDest: tried to write to non-client\n");
1810 return &svs.clients[entnum-1].message;
1813 return &sv.reliable_datagram;
1819 Host_Error("WriteDest: bad destination");
1826 void PF_WriteByte (void)
1828 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1831 void PF_WriteChar (void)
1833 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1836 void PF_WriteShort (void)
1838 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1841 void PF_WriteLong (void)
1843 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1846 void PF_WriteAngle (void)
1848 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1851 void PF_WriteCoord (void)
1853 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1856 void PF_WriteString (void)
1858 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1862 void PF_WriteEntity (void)
1864 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1867 //=============================================================================
1869 void PF_makestatic (void)
1874 ent = G_EDICT(OFS_PARM0);
1875 if (ent == sv.edicts)
1876 PF_WARNING("makestatic: can not modify world entity\n");
1878 PF_WARNING("makestatic: can not modify free entity\n");
1881 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1886 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1887 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1888 MSG_WriteShort (&sv.signon, ent->v->frame);
1892 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1893 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1894 MSG_WriteByte (&sv.signon, ent->v->frame);
1897 MSG_WriteByte (&sv.signon, ent->v->colormap);
1898 MSG_WriteByte (&sv.signon, ent->v->skin);
1899 for (i=0 ; i<3 ; i++)
1901 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1902 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1905 // throw the entity away now
1909 //=============================================================================
1916 void PF_setspawnparms (void)
1922 ent = G_EDICT(OFS_PARM0);
1923 i = NUM_FOR_EDICT(ent);
1924 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1926 Con_Print("tried to setspawnparms on a non-client\n");
1930 // copy spawn parms out of the client_t
1931 client = svs.clients + i-1;
1932 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1933 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1941 void PF_changelevel (void)
1945 // make sure we don't issue two changelevels
1946 if (svs.changelevel_issued)
1948 svs.changelevel_issued = true;
1950 s = G_STRING(OFS_PARM0);
1951 Cbuf_AddText (va("changelevel %s\n",s));
1956 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1961 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1966 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1973 Returns a vector of length < 1
1978 void PF_randomvec (void)
1983 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1984 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1985 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1987 while (DotProduct(temp, temp) >= 1);
1988 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1995 Returns a color vector indicating the lighting at the requested point.
1997 (Internal Operation note: actually measures the light beneath the point, just like
1998 the model lighting on the client)
2003 void PF_GetLight (void)
2005 vec3_t ambientcolor, diffusecolor, diffusenormal;
2007 p = G_VECTOR(OFS_PARM0);
2008 VectorClear(ambientcolor);
2009 VectorClear(diffusecolor);
2010 VectorClear(diffusenormal);
2011 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2012 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2013 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2016 void PF_registercvar (void)
2018 const char *name, *value;
2019 name = G_STRING(OFS_PARM0);
2020 value = G_STRING(OFS_PARM1);
2021 G_FLOAT(OFS_RETURN) = 0;
2023 // first check to see if it has already been defined
2024 if (Cvar_FindVar (name))
2027 // check for overlap with a command
2028 if (Cmd_Exists (name))
2030 Con_Printf("PF_registercvar: %s is a command\n", name);
2034 Cvar_Get(name, value, 0);
2036 G_FLOAT(OFS_RETURN) = 1; // success
2043 returns the minimum of two supplied floats
2050 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2052 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2053 else if (pr_argc >= 3)
2056 float f = G_FLOAT(OFS_PARM0);
2057 for (i = 1;i < pr_argc;i++)
2058 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2059 f = G_FLOAT((OFS_PARM0+i*3));
2060 G_FLOAT(OFS_RETURN) = f;
2064 G_FLOAT(OFS_RETURN) = 0;
2065 PF_WARNING("min: must supply at least 2 floats\n");
2073 returns the maximum of two supplied floats
2080 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2082 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2083 else if (pr_argc >= 3)
2086 float f = G_FLOAT(OFS_PARM0);
2087 for (i = 1;i < pr_argc;i++)
2088 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2089 f = G_FLOAT((OFS_PARM0+i*3));
2090 G_FLOAT(OFS_RETURN) = f;
2094 G_FLOAT(OFS_RETURN) = 0;
2095 PF_WARNING("max: must supply at least 2 floats\n");
2103 returns number bounded by supplied range
2105 min(min, value, max)
2108 void PF_bound (void)
2110 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2117 returns a raised to power b
2124 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2131 copies data from one entity to another
2133 copyentity(src, dst)
2136 void PF_copyentity (void)
2139 in = G_EDICT(OFS_PARM0);
2140 if (in == sv.edicts)
2141 PF_WARNING("copyentity: can not read world entity\n");
2143 PF_WARNING("copyentity: can not read free entity\n");
2144 out = G_EDICT(OFS_PARM1);
2145 if (out == sv.edicts)
2146 PF_WARNING("copyentity: can not modify world entity\n");
2148 PF_WARNING("copyentity: can not modify free entity\n");
2149 memcpy(out->v, in->v, progs->entityfields * 4);
2156 sets the color of a client and broadcasts the update to all connected clients
2158 setcolor(clientent, value)
2161 void PF_setcolor (void)
2167 entnum = G_EDICTNUM(OFS_PARM0);
2168 i = G_FLOAT(OFS_PARM1);
2170 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2172 Con_Print("tried to setcolor a non-client\n");
2176 client = svs.clients + entnum-1;
2179 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2181 client->edict->v->team = (i & 15) + 1;
2184 if (client->old_colors != client->colors)
2186 client->old_colors = client->colors;
2187 // send notification to all clients
2188 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2189 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2190 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2198 effect(origin, modelname, startframe, framecount, framerate)
2201 void PF_effect (void)
2205 s = G_STRING(OFS_PARM1);
2207 PF_WARNING("effect: no model specified\n");
2209 i = SV_ModelIndex(s, 1);
2211 PF_WARNING("effect: model not precached\n");
2212 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2215 void PF_te_blood (void)
2217 if (G_FLOAT(OFS_PARM2) < 1)
2219 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2220 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2222 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2223 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2224 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2226 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2227 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2228 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2230 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2233 void PF_te_bloodshower (void)
2235 if (G_FLOAT(OFS_PARM3) < 1)
2237 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2238 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2240 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2242 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2244 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2245 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2246 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2248 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2250 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2253 void PF_te_explosionrgb (void)
2255 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2256 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2258 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2259 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2260 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2262 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2263 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2264 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2267 void PF_te_particlecube (void)
2269 if (G_FLOAT(OFS_PARM3) < 1)
2271 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2272 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2274 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2275 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2276 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2278 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2279 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2280 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2282 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2283 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2284 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2286 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2288 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2289 // gravity true/false
2290 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2292 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2295 void PF_te_particlerain (void)
2297 if (G_FLOAT(OFS_PARM3) < 1)
2299 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2300 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2302 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2310 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2311 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2312 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2314 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2316 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2319 void PF_te_particlesnow (void)
2321 if (G_FLOAT(OFS_PARM3) < 1)
2323 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2324 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2326 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2334 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2335 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2336 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2338 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2340 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2343 void PF_te_spark (void)
2345 if (G_FLOAT(OFS_PARM2) < 1)
2347 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2348 MSG_WriteByte(&sv.datagram, TE_SPARK);
2350 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2351 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2352 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2354 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2355 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2356 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2358 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2361 void PF_te_gunshotquad (void)
2363 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2364 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2366 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2367 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2368 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2371 void PF_te_spikequad (void)
2373 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2374 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2376 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2377 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2378 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2381 void PF_te_superspikequad (void)
2383 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2384 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2386 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2387 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2388 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2391 void PF_te_explosionquad (void)
2393 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2394 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2396 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2397 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2398 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2401 void PF_te_smallflash (void)
2403 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2404 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2406 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2407 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2408 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2411 void PF_te_customflash (void)
2413 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2415 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2416 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2418 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2419 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2420 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2422 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2424 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2426 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2427 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2428 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2431 void PF_te_gunshot (void)
2433 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2434 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2436 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2437 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2438 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2441 void PF_te_spike (void)
2443 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2444 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2446 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2447 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2448 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2451 void PF_te_superspike (void)
2453 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2454 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2456 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2457 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2458 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2461 void PF_te_explosion (void)
2463 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2464 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2466 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2467 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2468 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2471 void PF_te_tarexplosion (void)
2473 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2474 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2476 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2477 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2478 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2481 void PF_te_wizspike (void)
2483 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2484 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2486 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2487 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2488 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2491 void PF_te_knightspike (void)
2493 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2494 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2496 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2497 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2498 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2501 void PF_te_lavasplash (void)
2503 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2504 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2506 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2507 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2508 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2511 void PF_te_teleport (void)
2513 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2514 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2516 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2517 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2518 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2521 void PF_te_explosion2 (void)
2523 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2524 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2526 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2527 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2528 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2530 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2531 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2534 void PF_te_lightning1 (void)
2536 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2537 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2539 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2541 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2542 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2543 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2545 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2546 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2547 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2550 void PF_te_lightning2 (void)
2552 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2553 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2555 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2557 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2558 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2559 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2561 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2562 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2563 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2566 void PF_te_lightning3 (void)
2568 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2569 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2571 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2573 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2574 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2575 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2577 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2578 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2579 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2582 void PF_te_beam (void)
2584 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2585 MSG_WriteByte(&sv.datagram, TE_BEAM);
2587 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2589 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2591 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2593 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2594 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2595 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2598 void PF_te_plasmaburn (void)
2600 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2601 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2602 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2603 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2604 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2607 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
2610 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2612 bestdist = 1000000000;
2614 for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2616 // clip original point to each triangle of the surface and find the
2617 // triangle that is closest
2618 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
2619 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
2620 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
2621 TriangleNormal(v[0], v[1], v[2], facenormal);
2622 VectorNormalize(facenormal);
2623 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2624 VectorMA(p, offsetdist, facenormal, temp);
2625 for (j = 0, k = 2;j < 3;k = j, j++)
2627 VectorSubtract(v[k], v[j], edgenormal);
2628 CrossProduct(edgenormal, facenormal, sidenormal);
2629 VectorNormalize(sidenormal);
2630 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2632 VectorMA(temp, offsetdist, sidenormal, temp);
2634 dist = VectorDistance2(temp, p);
2635 if (bestdist > dist)
2638 VectorCopy(temp, out);
2643 static msurface_t *getsurface(edict_t *ed, int surfacenum)
2647 if (!ed || ed->e->free)
2649 modelindex = ed->v->modelindex;
2650 if (modelindex < 1 || modelindex >= MAX_MODELS)
2652 model = sv.models[modelindex];
2653 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2655 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2659 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2660 void PF_getsurfacenumpoints(void)
2662 msurface_t *surface;
2663 // return 0 if no such surface
2664 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2666 G_FLOAT(OFS_RETURN) = 0;
2670 // note: this (incorrectly) assumes it is a simple polygon
2671 G_FLOAT(OFS_RETURN) = surface->num_vertices;
2673 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2674 void PF_getsurfacepoint(void)
2677 msurface_t *surface;
2679 VectorClear(G_VECTOR(OFS_RETURN));
2680 ed = G_EDICT(OFS_PARM0);
2681 if (!ed || ed->e->free)
2683 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2685 // note: this (incorrectly) assumes it is a simple polygon
2686 pointnum = G_FLOAT(OFS_PARM2);
2687 if (pointnum < 0 || pointnum >= surface->num_vertices)
2689 // FIXME: implement rotation/scaling
2690 VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2692 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2693 void PF_getsurfacenormal(void)
2695 msurface_t *surface;
2697 VectorClear(G_VECTOR(OFS_RETURN));
2698 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2700 // FIXME: implement rotation/scaling
2701 // note: this (incorrectly) assumes it is a simple polygon
2702 // note: this only returns the first triangle, so it doesn't work very
2703 // well for curved surfaces or arbitrary meshes
2704 TriangleNormal((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 3, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
2705 VectorNormalize(normal);
2706 VectorCopy(normal, G_VECTOR(OFS_RETURN));
2708 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2709 void PF_getsurfacetexture(void)
2711 msurface_t *surface;
2712 G_INT(OFS_RETURN) = 0;
2713 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2715 G_INT(OFS_RETURN) = PR_SetEngineString(surface->texture->name);
2717 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2718 void PF_getsurfacenearpoint(void)
2720 int surfacenum, best, modelindex;
2722 vec_t dist, bestdist;
2725 msurface_t *surface;
2727 G_FLOAT(OFS_RETURN) = -1;
2728 ed = G_EDICT(OFS_PARM0);
2729 point = G_VECTOR(OFS_PARM1);
2731 if (!ed || ed->e->free)
2733 modelindex = ed->v->modelindex;
2734 if (modelindex < 1 || modelindex >= MAX_MODELS)
2736 model = sv.models[modelindex];
2737 if (!model->num_surfaces)
2740 // FIXME: implement rotation/scaling
2741 VectorSubtract(point, ed->v->origin, p);
2743 bestdist = 1000000000;
2744 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2746 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2747 // first see if the nearest point on the surface's box is closer than the previous match
2748 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2749 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2750 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2751 dist = VectorLength2(clipped);
2752 if (dist < bestdist)
2754 // it is, check the nearest point on the actual geometry
2755 clippointtosurface(surface, p, clipped);
2756 VectorSubtract(clipped, p, clipped);
2757 dist += VectorLength2(clipped);
2758 if (dist < bestdist)
2760 // that's closer too, store it as the best match
2766 G_FLOAT(OFS_RETURN) = best;
2768 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2769 void PF_getsurfaceclippedpoint(void)
2772 msurface_t *surface;
2774 VectorClear(G_VECTOR(OFS_RETURN));
2775 ed = G_EDICT(OFS_PARM0);
2776 if (!ed || ed->e->free)
2778 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2780 // FIXME: implement rotation/scaling
2781 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2782 clippointtosurface(surface, p, out);
2783 // FIXME: implement rotation/scaling
2784 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2787 #define MAX_PRFILES 256
2789 qfile_t *pr_files[MAX_PRFILES];
2791 void PR_Files_Init(void)
2793 memset(pr_files, 0, sizeof(pr_files));
2796 void PR_Files_CloseAll(void)
2799 for (i = 0;i < MAX_PRFILES;i++)
2802 FS_Close(pr_files[i]);
2807 //float(string s) stof = #81; // get numerical value from a string
2810 char string[STRINGTEMP_LENGTH];
2811 PF_VarString(0, string, sizeof(string));
2812 G_FLOAT(OFS_RETURN) = atof(string);
2815 //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
2819 const char *modestring, *filename;
2820 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2821 if (pr_files[filenum] == NULL)
2823 if (filenum >= MAX_PRFILES)
2825 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2826 G_FLOAT(OFS_RETURN) = -2;
2829 mode = G_FLOAT(OFS_PARM1);
2832 case 0: // FILE_READ
2835 case 1: // FILE_APPEND
2838 case 2: // FILE_WRITE
2842 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2843 G_FLOAT(OFS_RETURN) = -3;
2846 filename = G_STRING(OFS_PARM0);
2847 // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2848 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false, false);
2850 if (pr_files[filenum] == NULL && modestring == "rb")
2851 pr_files[filenum] = FS_Open(filename, modestring, false, false);
2853 if (pr_files[filenum] == NULL)
2854 G_FLOAT(OFS_RETURN) = -1;
2856 G_FLOAT(OFS_RETURN) = filenum;
2859 //void(float fhandle) fclose = #111; // closes a file
2860 void PF_fclose(void)
2862 int filenum = G_FLOAT(OFS_PARM0);
2863 if (filenum < 0 || filenum >= MAX_PRFILES)
2865 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2868 if (pr_files[filenum] == NULL)
2870 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2873 FS_Close(pr_files[filenum]);
2874 pr_files[filenum] = NULL;
2877 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2881 static char string[STRINGTEMP_LENGTH];
2882 int filenum = G_FLOAT(OFS_PARM0);
2883 if (filenum < 0 || filenum >= MAX_PRFILES)
2885 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2888 if (pr_files[filenum] == NULL)
2890 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2896 c = FS_Getc(pr_files[filenum]);
2897 if (c == '\r' || c == '\n' || c < 0)
2899 if (end < STRINGTEMP_LENGTH - 1)
2903 // remove \n following \r
2906 c = FS_Getc(pr_files[filenum]);
2908 FS_UnGetc(pr_files[filenum], (unsigned char)c);
2910 if (developer.integer)
2911 Con_Printf("fgets: %s\n", string);
2913 G_INT(OFS_RETURN) = PR_SetEngineString(string);
2915 G_INT(OFS_RETURN) = 0;
2918 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2922 char string[STRINGTEMP_LENGTH];
2923 int filenum = G_FLOAT(OFS_PARM0);
2924 if (filenum < 0 || filenum >= MAX_PRFILES)
2926 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2929 if (pr_files[filenum] == NULL)
2931 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2934 PF_VarString(1, string, sizeof(string));
2935 if ((stringlength = strlen(string)))
2936 FS_Write(pr_files[filenum], string, stringlength);
2937 if (developer.integer)
2938 Con_Printf("fputs: %s\n", string);
2941 //float(string s) strlen = #114; // returns how many characters are in a string
2942 void PF_strlen(void)
2945 s = G_STRING(OFS_PARM0);
2947 G_FLOAT(OFS_RETURN) = strlen(s);
2949 G_FLOAT(OFS_RETURN) = 0;
2952 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2953 void PF_strcat(void)
2955 char *s = PR_GetTempString();
2956 PF_VarString(0, s, STRINGTEMP_LENGTH);
2957 G_INT(OFS_RETURN) = PR_SetEngineString(s);
2960 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2961 void PF_substring(void)
2963 int i, start, length;
2965 char *string = PR_GetTempString();
2966 s = G_STRING(OFS_PARM0);
2967 start = G_FLOAT(OFS_PARM1);
2968 length = G_FLOAT(OFS_PARM2);
2971 for (i = 0;i < start && *s;i++, s++);
2972 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2975 G_INT(OFS_RETURN) = PR_SetEngineString(string);
2978 //vector(string s) stov = #117; // returns vector value from a string
2981 char string[STRINGTEMP_LENGTH];
2982 PF_VarString(0, string, sizeof(string));
2983 Math_atov(string, G_VECTOR(OFS_RETURN));
2986 //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)
2987 void PF_strzone(void)
2991 in = G_STRING(OFS_PARM0);
2992 out = PR_AllocString(strlen(in) + 1);
2994 G_INT(OFS_RETURN) = PR_SetQCString(out);
2997 //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!!!)
2998 void PF_strunzone(void)
3000 PR_FreeString((char *)G_STRING(OFS_PARM0));
3003 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3004 //this function originally written by KrimZon, made shorter by LordHavoc
3005 void PF_clientcommand (void)
3007 client_t *temp_client;
3010 //find client for this entity
3011 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3012 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3014 Con_Print("PF_clientcommand: entity is not a client\n");
3018 temp_client = host_client;
3019 host_client = svs.clients + i;
3020 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3021 host_client = temp_client;
3024 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3025 //this function originally written by KrimZon, made shorter by LordHavoc
3026 //20040203: rewritten by LordHavoc (no longer uses allocations)
3028 char *tokens[256], tokenbuf[4096];
3029 void PF_tokenize (void)
3033 p = G_STRING(OFS_PARM0);
3037 while(COM_ParseToken(&p, false))
3039 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3041 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3043 tokens[num_tokens++] = tokenbuf + pos;
3044 strcpy(tokenbuf + pos, com_token);
3045 pos += strlen(com_token) + 1;
3048 G_FLOAT(OFS_RETURN) = num_tokens;
3051 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3052 //this function originally written by KrimZon, made shorter by LordHavoc
3055 int token_num = G_FLOAT(OFS_PARM0);
3056 if (token_num >= 0 && token_num < num_tokens)
3057 G_INT(OFS_RETURN) = PR_SetEngineString(tokens[token_num]);
3059 G_INT(OFS_RETURN) = PR_SetEngineString(NULL);
3062 //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)
3063 void PF_setattachment (void)
3065 edict_t *e = G_EDICT(OFS_PARM0);
3066 edict_t *tagentity = G_EDICT(OFS_PARM1);
3067 const char *tagname = G_STRING(OFS_PARM2);
3073 PF_WARNING("setattachment: can not modify world entity\n");
3075 PF_WARNING("setattachment: can not modify free entity\n");
3077 if (tagentity == NULL)
3078 tagentity = sv.edicts;
3080 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3082 v->edict = EDICT_TO_PROG(tagentity);
3084 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3087 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3089 modelindex = (int)tagentity->v->modelindex;
3090 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3092 v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->v->skin, tagname);
3094 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);
3097 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));
3101 /////////////////////////////////////////
3102 // DP_MD3_TAGINFO extension coded by VorteX
3104 int SV_GetTagIndex (edict_t *e, const char *tagname)
3109 i = e->v->modelindex;
3110 if (i < 1 || i >= MAX_MODELS)
3112 model = sv.models[i];
3114 return Mod_Alias_GetTagIndexForName(model, e->v->skin, tagname);
3117 // Warnings/errors code:
3118 // 0 - normal (everything all-right)
3121 // 3 - null or non-precached model
3122 // 4 - no tags with requested index
3123 // 5 - runaway loop at attachment chain
3124 extern cvar_t cl_bob;
3125 extern cvar_t cl_bobcycle;
3126 extern cvar_t cl_bobup;
3127 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3130 int modelindex, reqframe, attachloop;
3131 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3135 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3137 if (ent == sv.edicts)
3142 modelindex = (int)ent->v->modelindex;
3143 if (modelindex <= 0 || modelindex > MAX_MODELS)
3146 model = sv.models[modelindex];
3148 if (ent->v->frame >= 0 && ent->v->frame < model->numframes && model->animscenes)
3149 reqframe = model->animscenes[(int)ent->v->frame].firstframe;
3151 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3153 // get initial tag matrix
3156 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
3161 Matrix4x4_CreateIdentity(&tagmatrix);
3163 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3164 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3168 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3169 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3170 if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS && (model = sv.models[(int)attachent->v->modelindex]) && model->animscenes && attachent->v->frame >= 0 && attachent->v->frame < model->numframes)
3171 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->v->frame].firstframe, val->_float - 1, &attachmatrix);
3173 Matrix4x4_CreateIdentity(&attachmatrix);
3175 // apply transformation by child entity matrix
3176 val = GETEDICTFIELDVALUE(ent, eval_scale);
3177 if (val->_float == 0)
3179 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);
3180 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3181 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]);
3182 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]);
3183 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]);
3184 Matrix4x4_Copy(&tagmatrix, out);
3186 // finally transformate by matrix of tag on parent entity
3187 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3188 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];
3189 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];
3190 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];
3191 Matrix4x4_Copy(&tagmatrix, out);
3195 if (attachloop > 255) // prevent runaway looping
3198 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3201 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3202 val = GETEDICTFIELDVALUE(ent, eval_scale);
3203 if (val->_float == 0)
3205 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3206 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);
3207 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3208 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]);
3209 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]);
3210 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]);
3212 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3213 {// RENDER_VIEWMODEL magic
3214 Matrix4x4_Copy(&tagmatrix, out);
3215 ent = EDICT_NUM(val->edict);
3217 val = GETEDICTFIELDVALUE(ent, eval_scale);
3218 if (val->_float == 0)
3221 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);
3222 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3223 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]);
3224 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]);
3225 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]);
3228 // Cl_bob, ported from rendering code
3229 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3232 // LordHavoc: this code is *weird*, but not replacable (I think it
3233 // should be done in QC on the server, but oh well, quake is quake)
3234 // LordHavoc: figured out bobup: the time at which the sin is at 180
3235 // degrees (which allows lengthening or squishing the peak or valley)
3236 cycle = sv.time/cl_bobcycle.value;
3237 cycle -= (int)cycle;
3238 if (cycle < cl_bobup.value)
3239 cycle = sin(M_PI * cycle / cl_bobup.value);
3241 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3242 // bob is proportional to velocity in the xy plane
3243 // (don't count Z, or jumping messes it up)
3244 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3245 bob = bob*0.3 + bob*0.7*cycle;
3246 out->m[2][3] += bound(-7, bob, 4);
3253 //float(entity ent, string tagname) gettagindex;
3255 void PF_gettagindex (void)
3257 edict_t *ent = G_EDICT(OFS_PARM0);
3258 const char *tag_name = G_STRING(OFS_PARM1);
3259 int modelindex, tag_index;
3261 if (ent == sv.edicts)
3262 PF_WARNING("gettagindex: can't affect world entity\n");
3264 PF_WARNING("gettagindex: can't affect free entity\n");
3266 modelindex = (int)ent->v->modelindex;
3268 if (modelindex <= 0 || modelindex > MAX_MODELS)
3269 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3272 tag_index = SV_GetTagIndex(ent, tag_name);
3274 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3276 G_FLOAT(OFS_RETURN) = tag_index;
3279 //vector(entity ent, float tagindex) gettaginfo;
3280 void PF_gettaginfo (void)
3282 edict_t *e = G_EDICT(OFS_PARM0);
3283 int tagindex = (int)G_FLOAT(OFS_PARM1);
3284 matrix4x4_t tag_matrix;
3287 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3288 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3293 PF_WARNING("gettagindex: can't affect world entity\n");
3296 PF_WARNING("gettagindex: can't affect free entity\n");
3299 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3302 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3305 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3311 /////////////////////////////////////////
3312 // DP_QC_FS_SEARCH extension
3314 // qc fs search handling
3315 #define MAX_SEARCHES 128
3317 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3319 void PR_Search_Init(void)
3321 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3324 void PR_Search_Reset(void)
3327 // reset the fssearch list
3328 for(i = 0; i < MAX_SEARCHES; i++)
3329 if(pr_fssearchlist[i])
3330 FS_FreeSearch(pr_fssearchlist[i]);
3331 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3338 float search_begin(string pattern, float caseinsensitive, float quiet)
3341 void PF_search_begin(void)
3344 const char *pattern;
3345 int caseinsens, quiet;
3347 pattern = G_STRING(OFS_PARM0);
3348 if (!pattern || pattern[0] <= ' ')
3349 PF_ERROR("PF_search_begin: Bad string");
3351 caseinsens = G_FLOAT(OFS_PARM1);
3352 quiet = G_FLOAT(OFS_PARM2);
3354 for(handle = 0; handle < MAX_SEARCHES; handle++)
3355 if(!pr_fssearchlist[handle])
3358 if(handle >= MAX_SEARCHES)
3360 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3361 G_FLOAT(OFS_RETURN) = -2;
3365 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3366 G_FLOAT(OFS_RETURN) = -1;
3368 G_FLOAT(OFS_RETURN) = handle;
3375 void search_end(float handle)
3378 void PF_search_end(void)
3382 handle = G_FLOAT(OFS_PARM0);
3384 if(handle < 0 || handle >= MAX_SEARCHES)
3386 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3389 if(pr_fssearchlist[handle] == NULL)
3391 Con_Printf("PF_search_end: no such handle %i\n", handle);
3395 FS_FreeSearch(pr_fssearchlist[handle]);
3396 pr_fssearchlist[handle] = NULL;
3403 float search_getsize(float handle)
3406 void PF_search_getsize(void)
3410 handle = G_FLOAT(OFS_PARM0);
3412 if(handle < 0 || handle >= MAX_SEARCHES)
3414 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3417 if(pr_fssearchlist[handle] == NULL)
3419 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3423 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3428 VM_search_getfilename
3430 string search_getfilename(float handle, float num)
3433 void PF_search_getfilename(void)
3435 int handle, filenum;
3438 handle = G_FLOAT(OFS_PARM0);
3439 filenum = G_FLOAT(OFS_PARM1);
3441 if(handle < 0 || handle >= MAX_SEARCHES)
3443 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3446 if(pr_fssearchlist[handle] == NULL)
3448 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3451 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3453 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3457 tmp = PR_GetTempString();
3458 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3460 G_INT(OFS_RETURN) = PR_SetEngineString(tmp);
3463 void PF_cvar_string (void)
3469 str = G_STRING(OFS_PARM0);
3470 var = Cvar_FindVar (str);
3473 tmp = PR_GetTempString();
3474 strcpy(tmp, var->string);
3478 G_INT(OFS_RETURN) = PR_SetEngineString(tmp);
3481 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3482 void PF_dropclient (void)
3485 client_t *oldhostclient;
3486 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3487 if (clientnum < 0 || clientnum >= svs.maxclients)
3488 PF_WARNING("dropclient: not a client\n");
3489 if (!svs.clients[clientnum].active)
3490 PF_WARNING("dropclient: that client slot is not connected\n");
3491 oldhostclient = host_client;
3492 host_client = svs.clients + clientnum;
3493 SV_DropClient(false);
3494 host_client = oldhostclient;
3497 //entity() spawnclient (DP_SV_BOTCLIENT)
3498 void PF_spawnclient (void)
3502 pr_xfunction->builtinsprofile += 2;
3504 for (i = 0;i < svs.maxclients;i++)
3506 if (!svs.clients[i].active)
3508 pr_xfunction->builtinsprofile += 100;
3509 SV_ConnectClient (i, NULL);
3510 ed = EDICT_NUM(i + 1);
3517 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3518 void PF_clienttype (void)
3521 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3522 if (clientnum < 0 || clientnum >= svs.maxclients)
3523 G_FLOAT(OFS_RETURN) = 3;
3524 else if (!svs.clients[clientnum].active)
3525 G_FLOAT(OFS_RETURN) = 0;
3526 else if (svs.clients[clientnum].netconnection)
3527 G_FLOAT(OFS_RETURN) = 1;
3529 G_FLOAT(OFS_RETURN) = 2;
3532 builtin_t pr_builtin[] =
3535 PF_makevectors, // #1 void(entity e) makevectors
3536 PF_setorigin, // #2 void(entity e, vector o) setorigin
3537 PF_setmodel, // #3 void(entity e, string m) setmodel
3538 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3539 NULL, // #5 void(entity e, vector min, vector max) setabssize
3540 PF_break, // #6 void() break
3541 PF_random, // #7 float() random
3542 PF_sound, // #8 void(entity e, float chan, string samp) sound
3543 PF_normalize, // #9 vector(vector v) normalize
3544 PF_error, // #10 void(string e) error
3545 PF_objerror, // #11 void(string e) objerror
3546 PF_vlen, // #12 float(vector v) vlen
3547 PF_vectoyaw, // #13 float(vector v) vectoyaw
3548 PF_Spawn, // #14 entity() spawn
3549 PF_Remove, // #15 void(entity e) remove
3550 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3551 PF_checkclient, // #17 entity() clientlist
3552 PF_Find, // #18 entity(entity start, .string fld, string match) find
3553 PF_precache_sound, // #19 void(string s) precache_sound
3554 PF_precache_model, // #20 void(string s) precache_model
3555 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3556 PF_findradius, // #22 entity(vector org, float rad) findradius
3557 PF_bprint, // #23 void(string s) bprint
3558 PF_sprint, // #24 void(entity client, string s) sprint
3559 PF_dprint, // #25 void(string s) dprint
3560 PF_ftos, // #26 void(string s) ftos
3561 PF_vtos, // #27 void(string s) vtos
3562 PF_coredump, // #28 void() coredump
3563 PF_traceon, // #29 void() traceon
3564 PF_traceoff, // #30 void() traceoff
3565 PF_eprint, // #31 void(entity e) eprint
3566 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3568 PF_droptofloor, // #34 float() droptofloor
3569 PF_lightstyle, // #35 void(float style, string value) lightstyle
3570 PF_rint, // #36 float(float v) rint
3571 PF_floor, // #37 float(float v) floor
3572 PF_ceil, // #38 float(float v) ceil
3574 PF_checkbottom, // #40 float(entity e) checkbottom
3575 PF_pointcontents, // #41 float(vector v) pointcontents
3577 PF_fabs, // #43 float(float f) fabs
3578 PF_aim, // #44 vector(entity e, float speed) aim
3579 PF_cvar, // #45 float(string s) cvar
3580 PF_localcmd, // #46 void(string s) localcmd
3581 PF_nextent, // #47 entity(entity e) nextent
3582 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3583 PF_changeyaw, // #49 void() ChangeYaw
3585 PF_vectoangles, // #51 vector(vector v) vectoangles
3586 PF_WriteByte, // #52 void(float to, float f) WriteByte
3587 PF_WriteChar, // #53 void(float to, float f) WriteChar
3588 PF_WriteShort, // #54 void(float to, float f) WriteShort
3589 PF_WriteLong, // #55 void(float to, float f) WriteLong
3590 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3591 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3592 PF_WriteString, // #58 void(float to, string s) WriteString
3593 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3594 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3595 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3596 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3597 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3598 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3599 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3601 SV_MoveToGoal, // #67 void(float step) movetogoal
3602 PF_precache_file, // #68 string(string s) precache_file
3603 PF_makestatic, // #69 void(entity e) makestatic
3604 PF_changelevel, // #70 void(string s) changelevel
3606 PF_cvar_set, // #72 void(string var, string val) cvar_set
3607 PF_centerprint, // #73 void(entity client, strings) centerprint
3608 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3609 PF_precache_model, // #75 string(string s) precache_model2
3610 PF_precache_sound, // #76 string(string s) precache_sound2
3611 PF_precache_file, // #77 string(string s) precache_file2
3612 PF_setspawnparms, // #78 void(entity e) setspawnparms
3615 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3624 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3625 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3626 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3627 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3628 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3629 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3630 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3631 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3632 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3633 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3644 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3645 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3646 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3647 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3648 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3649 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3650 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3651 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3652 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3653 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3654 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3655 a a a a a a a a // #120-199
3656 a a a a a a a a a a // #200-299
3657 a a a a a a a a a a // #300-399
3658 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3659 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3660 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3661 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3662 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3663 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3664 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3665 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3666 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3667 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3668 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3669 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3670 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3671 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3672 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3673 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3674 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3675 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3676 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3677 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3678 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3679 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3680 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3681 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3682 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3683 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3684 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3685 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3686 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3687 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3688 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3689 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3690 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3691 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3692 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3693 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3694 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3695 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3696 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3697 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3698 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3699 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3700 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3701 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3702 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3703 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3704 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3705 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3706 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3707 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3708 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3709 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3710 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3711 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3712 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3713 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3718 a a a a // #460-499 (LordHavoc)
3721 builtin_t *pr_builtins = pr_builtin;
3722 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3724 void PR_Cmd_Init(void)
3730 void PR_Cmd_Shutdown(void)
3734 void PR_Cmd_Reset(void)
3737 PR_Files_CloseAll();