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(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 + 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_SetString(s);
1118 v = G_FLOAT(OFS_PARM0);
1119 G_FLOAT(OFS_RETURN) = fabs(v);
1125 s = PR_GetTempString();
1126 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1127 G_INT(OFS_RETURN) = PR_SetString(s);
1133 s = PR_GetTempString();
1134 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1135 G_INT(OFS_RETURN) = PR_SetString(s);
1138 void PF_Spawn (void)
1141 pr_xfunction->builtinsprofile += 20;
1146 void PF_Remove (void)
1149 pr_xfunction->builtinsprofile += 20;
1151 ed = G_EDICT(OFS_PARM0);
1152 if (ed == sv.edicts)
1153 PF_WARNING("remove: tried to remove world\n");
1154 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1155 PF_WARNING("remove: tried to remove a client\n");
1156 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1157 if (ed->e->free && developer.integer)
1158 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1163 // entity (entity start, .string field, string match) find = #5;
1171 e = G_EDICTNUM(OFS_PARM0);
1172 f = G_INT(OFS_PARM1);
1173 s = G_STRING(OFS_PARM2);
1176 RETURN_EDICT(sv.edicts);
1180 for (e++ ; e < sv.num_edicts ; e++)
1182 pr_xfunction->builtinsprofile++;
1196 RETURN_EDICT(sv.edicts);
1199 // LordHavoc: added this for searching float, int, and entity reference fields
1200 void PF_FindFloat (void)
1207 e = G_EDICTNUM(OFS_PARM0);
1208 f = G_INT(OFS_PARM1);
1209 s = G_FLOAT(OFS_PARM2);
1211 for (e++ ; e < sv.num_edicts ; e++)
1213 pr_xfunction->builtinsprofile++;
1217 if (E_FLOAT(ed,f) == s)
1224 RETURN_EDICT(sv.edicts);
1227 // chained search for strings in entity fields
1228 // entity(.string field, string match) findchain = #402;
1229 void PF_findchain (void)
1234 edict_t *ent, *chain;
1236 chain = (edict_t *)sv.edicts;
1238 f = G_INT(OFS_PARM0);
1239 s = G_STRING(OFS_PARM1);
1242 RETURN_EDICT(sv.edicts);
1246 ent = NEXT_EDICT(sv.edicts);
1247 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1249 pr_xfunction->builtinsprofile++;
1252 t = E_STRING(ent,f);
1258 ent->v->chain = EDICT_TO_PROG(chain);
1262 RETURN_EDICT(chain);
1265 // LordHavoc: chained search for float, int, and entity reference fields
1266 // entity(.string field, float match) findchainfloat = #403;
1267 void PF_findchainfloat (void)
1272 edict_t *ent, *chain;
1274 chain = (edict_t *)sv.edicts;
1276 f = G_INT(OFS_PARM0);
1277 s = G_FLOAT(OFS_PARM1);
1279 ent = NEXT_EDICT(sv.edicts);
1280 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1282 pr_xfunction->builtinsprofile++;
1285 if (E_FLOAT(ent,f) != s)
1288 ent->v->chain = EDICT_TO_PROG(chain);
1292 RETURN_EDICT(chain);
1295 // LordHavoc: search for flags in float fields
1296 void PF_findflags (void)
1303 e = G_EDICTNUM(OFS_PARM0);
1304 f = G_INT(OFS_PARM1);
1305 s = (int)G_FLOAT(OFS_PARM2);
1307 for (e++ ; e < sv.num_edicts ; e++)
1309 pr_xfunction->builtinsprofile++;
1313 if ((int)E_FLOAT(ed,f) & s)
1320 RETURN_EDICT(sv.edicts);
1323 // LordHavoc: chained search for flags in float fields
1324 void PF_findchainflags (void)
1329 edict_t *ent, *chain;
1331 chain = (edict_t *)sv.edicts;
1333 f = G_INT(OFS_PARM0);
1334 s = (int)G_FLOAT(OFS_PARM1);
1336 ent = NEXT_EDICT(sv.edicts);
1337 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1339 pr_xfunction->builtinsprofile++;
1342 if (!((int)E_FLOAT(ent,f) & s))
1345 ent->v->chain = EDICT_TO_PROG(chain);
1349 RETURN_EDICT(chain);
1352 void PR_CheckEmptyString (char *s)
1355 PF_ERROR("Bad string");
1358 void PF_precache_file (void)
1359 { // precache_file is only used to copy files with qcc, it does nothing
1360 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1364 void PF_precache_sound (void)
1366 SV_SoundIndex(G_STRING(OFS_PARM0), 2);
1367 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1370 void PF_precache_model (void)
1372 SV_ModelIndex(G_STRING(OFS_PARM0), 2);
1373 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1377 void PF_coredump (void)
1382 void PF_traceon (void)
1387 void PF_traceoff (void)
1392 void PF_eprint (void)
1394 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1401 float(float yaw, float dist) walkmove
1404 void PF_walkmove (void)
1412 // assume failure if it returns early
1413 G_FLOAT(OFS_RETURN) = 0;
1415 ent = PROG_TO_EDICT(pr_global_struct->self);
1416 if (ent == sv.edicts)
1417 PF_WARNING("walkmove: can not modify world entity\n");
1419 PF_WARNING("walkmove: can not modify free entity\n");
1420 yaw = G_FLOAT(OFS_PARM0);
1421 dist = G_FLOAT(OFS_PARM1);
1423 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1426 yaw = yaw*M_PI*2 / 360;
1428 move[0] = cos(yaw)*dist;
1429 move[1] = sin(yaw)*dist;
1432 // save program state, because SV_movestep may call other progs
1433 oldf = pr_xfunction;
1434 oldself = pr_global_struct->self;
1436 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1439 // restore program state
1440 pr_xfunction = oldf;
1441 pr_global_struct->self = oldself;
1451 void PF_droptofloor (void)
1457 // assume failure if it returns early
1458 G_FLOAT(OFS_RETURN) = 0;
1460 ent = PROG_TO_EDICT(pr_global_struct->self);
1461 if (ent == sv.edicts)
1462 PF_WARNING("droptofloor: can not modify world entity\n");
1464 PF_WARNING("droptofloor: can not modify free entity\n");
1466 VectorCopy (ent->v->origin, end);
1469 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1471 if (trace.fraction != 1)
1473 VectorCopy (trace.endpos, ent->v->origin);
1474 SV_LinkEdict (ent, false);
1475 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1476 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1477 G_FLOAT(OFS_RETURN) = 1;
1478 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1479 ent->e->suspendedinairflag = true;
1487 void(float style, string value) lightstyle
1490 void PF_lightstyle (void)
1497 style = G_FLOAT(OFS_PARM0);
1498 val = G_STRING(OFS_PARM1);
1500 // change the string in sv
1501 sv.lightstyles[style] = val;
1503 // send message to all clients on this server
1504 if (sv.state != ss_active)
1507 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1511 MSG_WriteChar (&client->message, svc_lightstyle);
1512 MSG_WriteChar (&client->message,style);
1513 MSG_WriteString (&client->message, val);
1521 f = G_FLOAT(OFS_PARM0);
1523 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1525 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1527 void PF_floor (void)
1529 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1533 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1542 void PF_checkbottom (void)
1544 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1552 void PF_pointcontents (void)
1554 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1561 entity nextent(entity)
1564 void PF_nextent (void)
1569 i = G_EDICTNUM(OFS_PARM0);
1572 pr_xfunction->builtinsprofile++;
1574 if (i == sv.num_edicts)
1576 RETURN_EDICT(sv.edicts);
1592 Pick a vector for the player to shoot along
1593 vector aim(entity, missilespeed)
1598 edict_t *ent, *check, *bestent;
1599 vec3_t start, dir, end, bestdir;
1602 float dist, bestdist;
1605 // assume failure if it returns early
1606 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1607 // if sv_aim is so high it can't possibly accept anything, skip out early
1608 if (sv_aim.value >= 1)
1611 ent = G_EDICT(OFS_PARM0);
1612 if (ent == sv.edicts)
1613 PF_WARNING("aim: can not use world entity\n");
1615 PF_WARNING("aim: can not use free entity\n");
1616 speed = G_FLOAT(OFS_PARM1);
1618 VectorCopy (ent->v->origin, start);
1621 // try sending a trace straight
1622 VectorCopy (pr_global_struct->v_forward, dir);
1623 VectorMA (start, 2048, dir, end);
1624 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1625 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1626 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1628 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1633 // try all possible entities
1634 VectorCopy (dir, bestdir);
1635 bestdist = sv_aim.value;
1638 check = NEXT_EDICT(sv.edicts);
1639 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1641 pr_xfunction->builtinsprofile++;
1642 if (check->v->takedamage != DAMAGE_AIM)
1646 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1647 continue; // don't aim at teammate
1648 for (j=0 ; j<3 ; j++)
1649 end[j] = check->v->origin[j]
1650 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1651 VectorSubtract (end, start, dir);
1652 VectorNormalize (dir);
1653 dist = DotProduct (dir, pr_global_struct->v_forward);
1654 if (dist < bestdist)
1655 continue; // to far to turn
1656 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1657 if (tr.ent == check)
1658 { // can shoot at this one
1666 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1667 dist = DotProduct (dir, pr_global_struct->v_forward);
1668 VectorScale (pr_global_struct->v_forward, dist, end);
1670 VectorNormalize (end);
1671 VectorCopy (end, G_VECTOR(OFS_RETURN));
1675 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1683 This was a major timewaster in progs, so it was converted to C
1686 void PF_changeyaw (void)
1689 float ideal, current, move, speed;
1691 ent = PROG_TO_EDICT(pr_global_struct->self);
1692 if (ent == sv.edicts)
1693 PF_WARNING("changeyaw: can not modify world entity\n");
1695 PF_WARNING("changeyaw: can not modify free entity\n");
1696 current = ANGLEMOD(ent->v->angles[1]);
1697 ideal = ent->v->ideal_yaw;
1698 speed = ent->v->yaw_speed;
1700 if (current == ideal)
1702 move = ideal - current;
1703 if (ideal > current)
1724 ent->v->angles[1] = ANGLEMOD (current + move);
1732 void PF_changepitch (void)
1735 float ideal, current, move, speed;
1738 ent = G_EDICT(OFS_PARM0);
1739 if (ent == sv.edicts)
1740 PF_WARNING("changepitch: can not modify world entity\n");
1742 PF_WARNING("changepitch: can not modify free entity\n");
1743 current = ANGLEMOD( ent->v->angles[0] );
1744 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1745 ideal = val->_float;
1748 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1751 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1752 speed = val->_float;
1755 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1759 if (current == ideal)
1761 move = ideal - current;
1762 if (ideal > current)
1783 ent->v->angles[0] = ANGLEMOD (current + move);
1787 ===============================================================================
1791 ===============================================================================
1794 #define MSG_BROADCAST 0 // unreliable to all
1795 #define MSG_ONE 1 // reliable to one (msg_entity)
1796 #define MSG_ALL 2 // reliable to all
1797 #define MSG_INIT 3 // write to the init string
1799 sizebuf_t *WriteDest (void)
1805 dest = G_FLOAT(OFS_PARM0);
1809 return &sv.datagram;
1812 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1813 entnum = NUM_FOR_EDICT(ent);
1814 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1815 Host_Error("WriteDest: tried to write to non-client\n");
1816 return &svs.clients[entnum-1].message;
1819 return &sv.reliable_datagram;
1825 Host_Error("WriteDest: bad destination");
1832 void PF_WriteByte (void)
1834 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1837 void PF_WriteChar (void)
1839 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1842 void PF_WriteShort (void)
1844 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1847 void PF_WriteLong (void)
1849 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1852 void PF_WriteAngle (void)
1854 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1857 void PF_WriteCoord (void)
1859 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1862 void PF_WriteString (void)
1864 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1868 void PF_WriteEntity (void)
1870 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1873 //=============================================================================
1875 void PF_makestatic (void)
1880 ent = G_EDICT(OFS_PARM0);
1881 if (ent == sv.edicts)
1882 PF_WARNING("makestatic: can not modify world entity\n");
1884 PF_WARNING("makestatic: can not modify free entity\n");
1887 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1892 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1893 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1894 MSG_WriteShort (&sv.signon, ent->v->frame);
1898 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1899 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1900 MSG_WriteByte (&sv.signon, ent->v->frame);
1903 MSG_WriteByte (&sv.signon, ent->v->colormap);
1904 MSG_WriteByte (&sv.signon, ent->v->skin);
1905 for (i=0 ; i<3 ; i++)
1907 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1908 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1911 // throw the entity away now
1915 //=============================================================================
1922 void PF_setspawnparms (void)
1928 ent = G_EDICT(OFS_PARM0);
1929 i = NUM_FOR_EDICT(ent);
1930 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1932 Con_Print("tried to setspawnparms on a non-client\n");
1936 // copy spawn parms out of the client_t
1937 client = svs.clients + i-1;
1938 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1939 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1947 void PF_changelevel (void)
1951 // make sure we don't issue two changelevels
1952 if (svs.changelevel_issued)
1954 svs.changelevel_issued = true;
1956 s = G_STRING(OFS_PARM0);
1957 Cbuf_AddText (va("changelevel %s\n",s));
1962 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1967 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1972 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1979 Returns a vector of length < 1
1984 void PF_randomvec (void)
1989 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1990 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1991 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1993 while (DotProduct(temp, temp) >= 1);
1994 VectorCopy (temp, G_VECTOR(OFS_RETURN));
2001 Returns a color vector indicating the lighting at the requested point.
2003 (Internal Operation note: actually measures the light beneath the point, just like
2004 the model lighting on the client)
2009 void PF_GetLight (void)
2011 vec3_t ambientcolor, diffusecolor, diffusenormal;
2013 p = G_VECTOR(OFS_PARM0);
2014 VectorClear(ambientcolor);
2015 VectorClear(diffusecolor);
2016 VectorClear(diffusenormal);
2017 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2018 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2019 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2022 void PF_registercvar (void)
2025 name = G_STRING(OFS_PARM0);
2026 value = G_STRING(OFS_PARM1);
2027 G_FLOAT(OFS_RETURN) = 0;
2029 // first check to see if it has already been defined
2030 if (Cvar_FindVar (name))
2033 // check for overlap with a command
2034 if (Cmd_Exists (name))
2036 Con_Printf("PF_registercvar: %s is a command\n", name);
2040 Cvar_Get(name, value, 0);
2042 G_FLOAT(OFS_RETURN) = 1; // success
2049 returns the minimum of two supplied floats
2056 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2058 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2059 else if (pr_argc >= 3)
2062 float f = G_FLOAT(OFS_PARM0);
2063 for (i = 1;i < pr_argc;i++)
2064 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2065 f = G_FLOAT((OFS_PARM0+i*3));
2066 G_FLOAT(OFS_RETURN) = f;
2070 G_FLOAT(OFS_RETURN) = 0;
2071 PF_WARNING("min: must supply at least 2 floats\n");
2079 returns the maximum of two supplied floats
2086 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2088 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2089 else if (pr_argc >= 3)
2092 float f = G_FLOAT(OFS_PARM0);
2093 for (i = 1;i < pr_argc;i++)
2094 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2095 f = G_FLOAT((OFS_PARM0+i*3));
2096 G_FLOAT(OFS_RETURN) = f;
2100 G_FLOAT(OFS_RETURN) = 0;
2101 PF_WARNING("max: must supply at least 2 floats\n");
2109 returns number bounded by supplied range
2111 min(min, value, max)
2114 void PF_bound (void)
2116 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2123 returns a raised to power b
2130 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2137 copies data from one entity to another
2139 copyentity(src, dst)
2142 void PF_copyentity (void)
2145 in = G_EDICT(OFS_PARM0);
2146 if (in == sv.edicts)
2147 PF_WARNING("copyentity: can not read world entity\n");
2149 PF_WARNING("copyentity: can not read free entity\n");
2150 out = G_EDICT(OFS_PARM1);
2151 if (out == sv.edicts)
2152 PF_WARNING("copyentity: can not modify world entity\n");
2154 PF_WARNING("copyentity: can not modify free entity\n");
2155 memcpy(out->v, in->v, progs->entityfields * 4);
2162 sets the color of a client and broadcasts the update to all connected clients
2164 setcolor(clientent, value)
2167 void PF_setcolor (void)
2173 entnum = G_EDICTNUM(OFS_PARM0);
2174 i = G_FLOAT(OFS_PARM1);
2176 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2178 Con_Print("tried to setcolor a non-client\n");
2182 client = svs.clients + entnum-1;
2185 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2187 client->edict->v->team = (i & 15) + 1;
2190 if (client->old_colors != client->colors)
2192 client->old_colors = client->colors;
2193 // send notification to all clients
2194 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2195 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2196 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2204 effect(origin, modelname, startframe, framecount, framerate)
2207 void PF_effect (void)
2211 s = G_STRING(OFS_PARM1);
2213 PF_WARNING("effect: no model specified\n");
2215 i = SV_ModelIndex(s, 1);
2217 PF_WARNING("effect: model not precached\n");
2218 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2221 void PF_te_blood (void)
2223 if (G_FLOAT(OFS_PARM2) < 1)
2225 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2226 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2228 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2229 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2230 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2232 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2233 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2234 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2236 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2239 void PF_te_bloodshower (void)
2241 if (G_FLOAT(OFS_PARM3) < 1)
2243 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2244 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2246 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2247 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2248 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2250 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2251 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2252 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2254 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2256 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2259 void PF_te_explosionrgb (void)
2261 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2262 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2264 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2265 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2266 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2268 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2269 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2270 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2273 void PF_te_particlecube (void)
2275 if (G_FLOAT(OFS_PARM3) < 1)
2277 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2278 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2280 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2281 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2282 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2284 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2285 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2288 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2290 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2292 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2294 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2295 // gravity true/false
2296 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2298 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2301 void PF_te_particlerain (void)
2303 if (G_FLOAT(OFS_PARM3) < 1)
2305 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2306 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2308 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2309 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2310 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2312 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2313 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2314 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2316 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2317 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2318 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2320 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2322 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2325 void PF_te_particlesnow (void)
2327 if (G_FLOAT(OFS_PARM3) < 1)
2329 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2330 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2332 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2334 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2336 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2337 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2338 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2340 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2341 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2342 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2344 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2346 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2349 void PF_te_spark (void)
2351 if (G_FLOAT(OFS_PARM2) < 1)
2353 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2354 MSG_WriteByte(&sv.datagram, TE_SPARK);
2356 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2357 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2358 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2360 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2361 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2362 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2364 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2367 void PF_te_gunshotquad (void)
2369 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2370 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
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_spikequad (void)
2379 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2380 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
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_superspikequad (void)
2389 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2390 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
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_explosionquad (void)
2399 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2400 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
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_smallflash (void)
2409 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2410 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2412 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2413 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2414 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2417 void PF_te_customflash (void)
2419 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2421 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2424 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2425 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2426 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2428 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2430 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2432 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2433 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2434 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2437 void PF_te_gunshot (void)
2439 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2440 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
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_spike (void)
2449 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2450 MSG_WriteByte(&sv.datagram, TE_SPIKE);
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_superspike (void)
2459 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
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_explosion (void)
2469 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2470 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
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_tarexplosion (void)
2479 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2480 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
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_wizspike (void)
2489 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2490 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
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_knightspike (void)
2499 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2500 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
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_lavasplash (void)
2509 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2510 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
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_teleport (void)
2519 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2520 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
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);
2527 void PF_te_explosion2 (void)
2529 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2530 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2532 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2533 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2534 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2536 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2537 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2540 void PF_te_lightning1 (void)
2542 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2543 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2545 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2547 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2548 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2549 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2551 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2552 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2553 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2556 void PF_te_lightning2 (void)
2558 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2559 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2561 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2563 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2564 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2565 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2567 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2568 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2569 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2572 void PF_te_lightning3 (void)
2574 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2575 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2577 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2579 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2580 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2581 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2583 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2584 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2585 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2588 void PF_te_beam (void)
2590 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2591 MSG_WriteByte(&sv.datagram, TE_BEAM);
2593 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2595 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2596 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2597 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2599 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2600 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2601 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2604 void PF_te_plasmaburn (void)
2606 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2607 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2608 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2609 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2610 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2613 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
2616 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2618 bestdist = 1000000000;
2620 for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2622 // clip original point to each triangle of the surface and find the
2623 // triangle that is closest
2624 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
2625 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
2626 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
2627 TriangleNormal(v[0], v[1], v[2], facenormal);
2628 VectorNormalize(facenormal);
2629 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2630 VectorMA(p, offsetdist, facenormal, temp);
2631 for (j = 0, k = 2;j < 3;k = j, j++)
2633 VectorSubtract(v[k], v[j], edgenormal);
2634 CrossProduct(edgenormal, facenormal, sidenormal);
2635 VectorNormalize(sidenormal);
2636 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2638 VectorMA(temp, offsetdist, sidenormal, temp);
2640 dist = VectorDistance2(temp, p);
2641 if (bestdist > dist)
2644 VectorCopy(temp, out);
2649 static msurface_t *getsurface(edict_t *ed, int surfacenum)
2653 if (!ed || ed->e->free)
2655 modelindex = ed->v->modelindex;
2656 if (modelindex < 1 || modelindex >= MAX_MODELS)
2658 model = sv.models[modelindex];
2659 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2661 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2665 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2666 void PF_getsurfacenumpoints(void)
2668 msurface_t *surface;
2669 // return 0 if no such surface
2670 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2672 G_FLOAT(OFS_RETURN) = 0;
2676 // note: this (incorrectly) assumes it is a simple polygon
2677 G_FLOAT(OFS_RETURN) = surface->num_vertices;
2679 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2680 void PF_getsurfacepoint(void)
2683 msurface_t *surface;
2685 VectorClear(G_VECTOR(OFS_RETURN));
2686 ed = G_EDICT(OFS_PARM0);
2687 if (!ed || ed->e->free)
2689 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2691 // note: this (incorrectly) assumes it is a simple polygon
2692 pointnum = G_FLOAT(OFS_PARM2);
2693 if (pointnum < 0 || pointnum >= surface->num_vertices)
2695 // FIXME: implement rotation/scaling
2696 VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2698 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2699 void PF_getsurfacenormal(void)
2701 msurface_t *surface;
2703 VectorClear(G_VECTOR(OFS_RETURN));
2704 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2706 // FIXME: implement rotation/scaling
2707 // note: this (incorrectly) assumes it is a simple polygon
2708 // note: this only returns the first triangle, so it doesn't work very
2709 // well for curved surfaces or arbitrary meshes
2710 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);
2711 VectorNormalize(normal);
2712 VectorCopy(normal, G_VECTOR(OFS_RETURN));
2714 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2715 void PF_getsurfacetexture(void)
2717 msurface_t *surface;
2718 G_INT(OFS_RETURN) = 0;
2719 if (!(surface = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2721 G_INT(OFS_RETURN) = PR_SetString(surface->texture->name);
2723 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2724 void PF_getsurfacenearpoint(void)
2726 int surfacenum, best, modelindex;
2728 vec_t dist, bestdist;
2731 msurface_t *surface;
2733 G_FLOAT(OFS_RETURN) = -1;
2734 ed = G_EDICT(OFS_PARM0);
2735 point = G_VECTOR(OFS_PARM1);
2737 if (!ed || ed->e->free)
2739 modelindex = ed->v->modelindex;
2740 if (modelindex < 1 || modelindex >= MAX_MODELS)
2742 model = sv.models[modelindex];
2743 if (!model->num_surfaces)
2746 // FIXME: implement rotation/scaling
2747 VectorSubtract(point, ed->v->origin, p);
2749 bestdist = 1000000000;
2750 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2752 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2753 // first see if the nearest point on the surface's box is closer than the previous match
2754 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2755 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2756 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2757 dist = VectorLength2(clipped);
2758 if (dist < bestdist)
2760 // it is, check the nearest point on the actual geometry
2761 clippointtosurface(surface, p, clipped);
2762 VectorSubtract(clipped, p, clipped);
2763 dist += VectorLength2(clipped);
2764 if (dist < bestdist)
2766 // that's closer too, store it as the best match
2772 G_FLOAT(OFS_RETURN) = best;
2774 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2775 void PF_getsurfaceclippedpoint(void)
2778 msurface_t *surface;
2780 VectorClear(G_VECTOR(OFS_RETURN));
2781 ed = G_EDICT(OFS_PARM0);
2782 if (!ed || ed->e->free)
2784 if (!(surface = getsurface(ed, G_FLOAT(OFS_PARM1))))
2786 // FIXME: implement rotation/scaling
2787 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2788 clippointtosurface(surface, p, out);
2789 // FIXME: implement rotation/scaling
2790 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2793 #define MAX_PRFILES 256
2795 qfile_t *pr_files[MAX_PRFILES];
2797 void PR_Files_Init(void)
2799 memset(pr_files, 0, sizeof(pr_files));
2802 void PR_Files_CloseAll(void)
2805 for (i = 0;i < MAX_PRFILES;i++)
2808 FS_Close(pr_files[i]);
2813 //float(string s) stof = #81; // get numerical value from a string
2816 char string[STRINGTEMP_LENGTH];
2817 PF_VarString(0, string, sizeof(string));
2818 G_FLOAT(OFS_RETURN) = atof(string);
2821 //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
2825 char *modestring, *filename;
2826 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2827 if (pr_files[filenum] == NULL)
2829 if (filenum >= MAX_PRFILES)
2831 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2832 G_FLOAT(OFS_RETURN) = -2;
2835 mode = G_FLOAT(OFS_PARM1);
2838 case 0: // FILE_READ
2841 case 1: // FILE_APPEND
2844 case 2: // FILE_WRITE
2848 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2849 G_FLOAT(OFS_RETURN) = -3;
2852 filename = G_STRING(OFS_PARM0);
2853 // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2854 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false, false);
2856 if (pr_files[filenum] == NULL && modestring == "rb")
2857 pr_files[filenum] = FS_Open(filename, modestring, false, false);
2859 if (pr_files[filenum] == NULL)
2860 G_FLOAT(OFS_RETURN) = -1;
2862 G_FLOAT(OFS_RETURN) = filenum;
2865 //void(float fhandle) fclose = #111; // closes a file
2866 void PF_fclose(void)
2868 int filenum = G_FLOAT(OFS_PARM0);
2869 if (filenum < 0 || filenum >= MAX_PRFILES)
2871 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2874 if (pr_files[filenum] == NULL)
2876 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2879 FS_Close(pr_files[filenum]);
2880 pr_files[filenum] = NULL;
2883 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2887 static char string[STRINGTEMP_LENGTH];
2888 int filenum = G_FLOAT(OFS_PARM0);
2889 if (filenum < 0 || filenum >= MAX_PRFILES)
2891 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2894 if (pr_files[filenum] == NULL)
2896 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2902 c = FS_Getc(pr_files[filenum]);
2903 if (c == '\r' || c == '\n' || c < 0)
2905 if (end < STRINGTEMP_LENGTH - 1)
2909 // remove \n following \r
2912 c = FS_Getc(pr_files[filenum]);
2914 FS_UnGetc(pr_files[filenum], (unsigned char)c);
2916 if (developer.integer)
2917 Con_Printf("fgets: %s\n", string);
2919 G_INT(OFS_RETURN) = PR_SetString(string);
2921 G_INT(OFS_RETURN) = 0;
2924 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2928 char string[STRINGTEMP_LENGTH];
2929 int filenum = G_FLOAT(OFS_PARM0);
2930 if (filenum < 0 || filenum >= MAX_PRFILES)
2932 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2935 if (pr_files[filenum] == NULL)
2937 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2940 PF_VarString(1, string, sizeof(string));
2941 if ((stringlength = strlen(string)))
2942 FS_Write(pr_files[filenum], string, stringlength);
2943 if (developer.integer)
2944 Con_Printf("fputs: %s\n", string);
2947 //float(string s) strlen = #114; // returns how many characters are in a string
2948 void PF_strlen(void)
2951 s = G_STRING(OFS_PARM0);
2953 G_FLOAT(OFS_RETURN) = strlen(s);
2955 G_FLOAT(OFS_RETURN) = 0;
2958 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2959 void PF_strcat(void)
2961 char *s = PR_GetTempString();
2962 PF_VarString(0, s, STRINGTEMP_LENGTH);
2963 G_INT(OFS_RETURN) = PR_SetString(s);
2966 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2967 void PF_substring(void)
2969 int i, start, length;
2970 char *s, *string = PR_GetTempString();
2971 s = G_STRING(OFS_PARM0);
2972 start = G_FLOAT(OFS_PARM1);
2973 length = G_FLOAT(OFS_PARM2);
2976 for (i = 0;i < start && *s;i++, s++);
2977 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2980 G_INT(OFS_RETURN) = PR_SetString(string);
2983 //vector(string s) stov = #117; // returns vector value from a string
2986 char string[STRINGTEMP_LENGTH];
2987 PF_VarString(0, string, sizeof(string));
2988 Math_atov(string, G_VECTOR(OFS_RETURN));
2991 //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)
2992 void PF_strzone(void)
2995 in = G_STRING(OFS_PARM0);
2996 out = PR_Alloc(strlen(in) + 1);
2998 G_INT(OFS_RETURN) = PR_SetString(out);
3001 //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!!!)
3002 void PF_strunzone(void)
3004 PR_Free(G_STRING(OFS_PARM0));
3007 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3008 //this function originally written by KrimZon, made shorter by LordHavoc
3009 void PF_clientcommand (void)
3011 client_t *temp_client;
3014 //find client for this entity
3015 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3016 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3018 Con_Print("PF_clientcommand: entity is not a client\n");
3022 temp_client = host_client;
3023 host_client = svs.clients + i;
3024 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3025 host_client = temp_client;
3028 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3029 //this function originally written by KrimZon, made shorter by LordHavoc
3030 //20040203: rewritten by LordHavoc (no longer uses allocations)
3032 char *tokens[256], tokenbuf[4096];
3033 void PF_tokenize (void)
3037 p = G_STRING(OFS_PARM0);
3041 while(COM_ParseToken(&p, false))
3043 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3045 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3047 tokens[num_tokens++] = tokenbuf + pos;
3048 strcpy(tokenbuf + pos, com_token);
3049 pos += strlen(com_token) + 1;
3052 G_FLOAT(OFS_RETURN) = num_tokens;
3055 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3056 //this function originally written by KrimZon, made shorter by LordHavoc
3059 int token_num = G_FLOAT(OFS_PARM0);
3060 if (token_num >= 0 && token_num < num_tokens)
3061 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3063 G_INT(OFS_RETURN) = PR_SetString("");
3066 //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)
3067 void PF_setattachment (void)
3069 edict_t *e = G_EDICT(OFS_PARM0);
3070 edict_t *tagentity = G_EDICT(OFS_PARM1);
3071 char *tagname = G_STRING(OFS_PARM2);
3077 PF_WARNING("setattachment: can not modify world entity\n");
3079 PF_WARNING("setattachment: can not modify free entity\n");
3081 if (tagentity == NULL)
3082 tagentity = sv.edicts;
3084 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3086 v->edict = EDICT_TO_PROG(tagentity);
3088 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3091 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3093 modelindex = (int)tagentity->v->modelindex;
3094 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3096 v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->v->skin, tagname);
3098 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);
3101 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));
3105 /////////////////////////////////////////
3106 // DP_MD3_TAGINFO extension coded by VorteX
3108 int SV_GetTagIndex (edict_t *e, char *tagname)
3113 i = e->v->modelindex;
3114 if (i < 1 || i >= MAX_MODELS)
3116 model = sv.models[i];
3118 return Mod_Alias_GetTagIndexForName(model, e->v->skin, tagname);
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, 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];
3152 if (ent->v->frame >= 0 && ent->v->frame < model->numframes && model->animscenes)
3153 reqframe = model->animscenes[(int)ent->v->frame].firstframe;
3155 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3157 // get initial tag matrix
3160 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
3165 Matrix4x4_CreateIdentity(&tagmatrix);
3167 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3168 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3172 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3173 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3174 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)
3175 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->v->frame].firstframe, val->_float - 1, &attachmatrix);
3177 Matrix4x4_CreateIdentity(&attachmatrix);
3179 // apply transformation by child entity matrix
3180 val = GETEDICTFIELDVALUE(ent, eval_scale);
3181 if (val->_float == 0)
3183 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);
3184 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3185 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]);
3186 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]);
3187 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]);
3188 Matrix4x4_Copy(&tagmatrix, out);
3190 // finally transformate by matrix of tag on parent entity
3191 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3192 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];
3193 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];
3194 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];
3195 Matrix4x4_Copy(&tagmatrix, out);
3199 if (attachloop > 255) // prevent runaway looping
3202 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3205 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3206 val = GETEDICTFIELDVALUE(ent, eval_scale);
3207 if (val->_float == 0)
3209 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3210 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);
3211 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3212 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]);
3213 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]);
3214 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]);
3216 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3217 {// RENDER_VIEWMODEL magic
3218 Matrix4x4_Copy(&tagmatrix, out);
3219 ent = EDICT_NUM(val->edict);
3221 val = GETEDICTFIELDVALUE(ent, eval_scale);
3222 if (val->_float == 0)
3225 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);
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]);
3232 // Cl_bob, ported from rendering code
3233 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3236 // LordHavoc: this code is *weird*, but not replacable (I think it
3237 // should be done in QC on the server, but oh well, quake is quake)
3238 // LordHavoc: figured out bobup: the time at which the sin is at 180
3239 // degrees (which allows lengthening or squishing the peak or valley)
3240 cycle = sv.time/cl_bobcycle.value;
3241 cycle -= (int)cycle;
3242 if (cycle < cl_bobup.value)
3243 cycle = sin(M_PI * cycle / cl_bobup.value);
3245 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3246 // bob is proportional to velocity in the xy plane
3247 // (don't count Z, or jumping messes it up)
3248 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3249 bob = bob*0.3 + bob*0.7*cycle;
3250 out->m[2][3] += bound(-7, bob, 4);
3257 //float(entity ent, string tagname) gettagindex;
3259 void PF_gettagindex (void)
3261 edict_t *ent = G_EDICT(OFS_PARM0);
3262 char *tag_name = G_STRING(OFS_PARM1);
3263 int modelindex, tag_index;
3265 if (ent == sv.edicts)
3266 PF_WARNING("gettagindex: can't affect world entity\n");
3268 PF_WARNING("gettagindex: can't affect free entity\n");
3270 modelindex = (int)ent->v->modelindex;
3272 if (modelindex <= 0 || modelindex > MAX_MODELS)
3273 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3276 tag_index = SV_GetTagIndex(ent, tag_name);
3278 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3280 G_FLOAT(OFS_RETURN) = tag_index;
3283 //vector(entity ent, float tagindex) gettaginfo;
3284 void PF_gettaginfo (void)
3286 edict_t *e = G_EDICT(OFS_PARM0);
3287 int tagindex = (int)G_FLOAT(OFS_PARM1);
3288 matrix4x4_t tag_matrix;
3291 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3292 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3297 PF_WARNING("gettagindex: can't affect world entity\n");
3300 PF_WARNING("gettagindex: can't affect free entity\n");
3303 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3306 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3309 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3315 /////////////////////////////////////////
3316 // DP_QC_FS_SEARCH extension
3318 // qc fs search handling
3319 #define MAX_SEARCHES 128
3321 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3323 void PR_Search_Init(void)
3325 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3328 void PR_Search_Reset(void)
3331 // reset the fssearch list
3332 for(i = 0; i < MAX_SEARCHES; i++)
3333 if(pr_fssearchlist[i])
3334 FS_FreeSearch(pr_fssearchlist[i]);
3335 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3342 float search_begin(string pattern, float caseinsensitive, float quiet)
3345 void PF_search_begin(void)
3349 int caseinsens, quiet;
3351 pattern = G_STRING(OFS_PARM0);
3353 PR_CheckEmptyString(pattern);
3355 caseinsens = G_FLOAT(OFS_PARM1);
3356 quiet = G_FLOAT(OFS_PARM2);
3358 for(handle = 0; handle < MAX_SEARCHES; handle++)
3359 if(!pr_fssearchlist[handle])
3362 if(handle >= MAX_SEARCHES)
3364 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3365 G_FLOAT(OFS_RETURN) = -2;
3369 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3370 G_FLOAT(OFS_RETURN) = -1;
3372 G_FLOAT(OFS_RETURN) = handle;
3379 void search_end(float handle)
3382 void PF_search_end(void)
3386 handle = G_FLOAT(OFS_PARM0);
3388 if(handle < 0 || handle >= MAX_SEARCHES)
3390 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3393 if(pr_fssearchlist[handle] == NULL)
3395 Con_Printf("PF_search_end: no such handle %i\n", handle);
3399 FS_FreeSearch(pr_fssearchlist[handle]);
3400 pr_fssearchlist[handle] = NULL;
3407 float search_getsize(float handle)
3410 void PF_search_getsize(void)
3414 handle = G_FLOAT(OFS_PARM0);
3416 if(handle < 0 || handle >= MAX_SEARCHES)
3418 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3421 if(pr_fssearchlist[handle] == NULL)
3423 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3427 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3432 VM_search_getfilename
3434 string search_getfilename(float handle, float num)
3437 void PF_search_getfilename(void)
3439 int handle, filenum;
3442 handle = G_FLOAT(OFS_PARM0);
3443 filenum = G_FLOAT(OFS_PARM1);
3445 if(handle < 0 || handle >= MAX_SEARCHES)
3447 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3450 if(pr_fssearchlist[handle] == NULL)
3452 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3455 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3457 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3461 tmp = PR_GetTempString();
3462 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3464 G_INT(OFS_RETURN) = PR_SetString(tmp);
3467 void PF_cvar_string (void)
3473 str = G_STRING(OFS_PARM0);
3474 var = Cvar_FindVar (str);
3477 tmp = PR_GetTempString();
3478 strcpy(tmp, var->string);
3482 G_INT(OFS_RETURN) = PR_SetString(tmp);
3485 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3486 void PF_dropclient (void)
3489 client_t *oldhostclient;
3490 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3491 if (clientnum < 0 || clientnum >= svs.maxclients)
3492 PF_WARNING("dropclient: not a client\n");
3493 if (!svs.clients[clientnum].active)
3494 PF_WARNING("dropclient: that client slot is not connected\n");
3495 oldhostclient = host_client;
3496 host_client = svs.clients + clientnum;
3497 SV_DropClient(false);
3498 host_client = oldhostclient;
3501 //entity() spawnclient (DP_SV_BOTCLIENT)
3502 void PF_spawnclient (void)
3506 pr_xfunction->builtinsprofile += 2;
3508 for (i = 0;i < svs.maxclients;i++)
3510 if (!svs.clients[i].active)
3512 pr_xfunction->builtinsprofile += 100;
3513 SV_ConnectClient (i, NULL);
3514 ed = EDICT_NUM(i + 1);
3521 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3522 void PF_clienttype (void)
3525 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3526 if (clientnum < 0 || clientnum >= svs.maxclients)
3527 G_FLOAT(OFS_RETURN) = 3;
3528 else if (!svs.clients[clientnum].active)
3529 G_FLOAT(OFS_RETURN) = 0;
3530 else if (svs.clients[clientnum].netconnection)
3531 G_FLOAT(OFS_RETURN) = 1;
3533 G_FLOAT(OFS_RETURN) = 2;
3536 builtin_t pr_builtin[] =
3539 PF_makevectors, // #1 void(entity e) makevectors
3540 PF_setorigin, // #2 void(entity e, vector o) setorigin
3541 PF_setmodel, // #3 void(entity e, string m) setmodel
3542 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3543 NULL, // #5 void(entity e, vector min, vector max) setabssize
3544 PF_break, // #6 void() break
3545 PF_random, // #7 float() random
3546 PF_sound, // #8 void(entity e, float chan, string samp) sound
3547 PF_normalize, // #9 vector(vector v) normalize
3548 PF_error, // #10 void(string e) error
3549 PF_objerror, // #11 void(string e) objerror
3550 PF_vlen, // #12 float(vector v) vlen
3551 PF_vectoyaw, // #13 float(vector v) vectoyaw
3552 PF_Spawn, // #14 entity() spawn
3553 PF_Remove, // #15 void(entity e) remove
3554 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3555 PF_checkclient, // #17 entity() clientlist
3556 PF_Find, // #18 entity(entity start, .string fld, string match) find
3557 PF_precache_sound, // #19 void(string s) precache_sound
3558 PF_precache_model, // #20 void(string s) precache_model
3559 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3560 PF_findradius, // #22 entity(vector org, float rad) findradius
3561 PF_bprint, // #23 void(string s) bprint
3562 PF_sprint, // #24 void(entity client, string s) sprint
3563 PF_dprint, // #25 void(string s) dprint
3564 PF_ftos, // #26 void(string s) ftos
3565 PF_vtos, // #27 void(string s) vtos
3566 PF_coredump, // #28 void() coredump
3567 PF_traceon, // #29 void() traceon
3568 PF_traceoff, // #30 void() traceoff
3569 PF_eprint, // #31 void(entity e) eprint
3570 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3572 PF_droptofloor, // #34 float() droptofloor
3573 PF_lightstyle, // #35 void(float style, string value) lightstyle
3574 PF_rint, // #36 float(float v) rint
3575 PF_floor, // #37 float(float v) floor
3576 PF_ceil, // #38 float(float v) ceil
3578 PF_checkbottom, // #40 float(entity e) checkbottom
3579 PF_pointcontents, // #41 float(vector v) pointcontents
3581 PF_fabs, // #43 float(float f) fabs
3582 PF_aim, // #44 vector(entity e, float speed) aim
3583 PF_cvar, // #45 float(string s) cvar
3584 PF_localcmd, // #46 void(string s) localcmd
3585 PF_nextent, // #47 entity(entity e) nextent
3586 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3587 PF_changeyaw, // #49 void() ChangeYaw
3589 PF_vectoangles, // #51 vector(vector v) vectoangles
3590 PF_WriteByte, // #52 void(float to, float f) WriteByte
3591 PF_WriteChar, // #53 void(float to, float f) WriteChar
3592 PF_WriteShort, // #54 void(float to, float f) WriteShort
3593 PF_WriteLong, // #55 void(float to, float f) WriteLong
3594 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3595 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3596 PF_WriteString, // #58 void(float to, string s) WriteString
3597 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3598 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3599 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3600 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3601 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3602 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3603 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3605 SV_MoveToGoal, // #67 void(float step) movetogoal
3606 PF_precache_file, // #68 string(string s) precache_file
3607 PF_makestatic, // #69 void(entity e) makestatic
3608 PF_changelevel, // #70 void(string s) changelevel
3610 PF_cvar_set, // #72 void(string var, string val) cvar_set
3611 PF_centerprint, // #73 void(entity client, strings) centerprint
3612 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3613 PF_precache_model, // #75 string(string s) precache_model2
3614 PF_precache_sound, // #76 string(string s) precache_sound2
3615 PF_precache_file, // #77 string(string s) precache_file2
3616 PF_setspawnparms, // #78 void(entity e) setspawnparms
3619 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3628 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3629 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3630 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3631 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3632 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3633 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3634 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3635 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3636 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3637 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3648 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3649 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3650 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3651 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3652 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3653 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3654 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3655 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3656 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3657 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3658 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3659 a a a a a a a a // #120-199
3660 a a a a a a a a a a // #200-299
3661 a a a a a a a a a a // #300-399
3662 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3663 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3664 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3665 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3666 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3667 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3668 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3669 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3670 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3671 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3672 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3673 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3674 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3675 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3676 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3677 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3678 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3679 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3680 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3681 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3682 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3683 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3684 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3685 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3686 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3687 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3688 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3689 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3690 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3691 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3692 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3693 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3694 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3695 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3696 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3697 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3698 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3699 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3700 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3701 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3702 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3703 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3704 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3705 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3706 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3707 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3708 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3709 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3710 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3711 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3712 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3713 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3714 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3715 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3716 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3717 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3722 a a a a // #460-499 (LordHavoc)
3725 builtin_t *pr_builtins = pr_builtin;
3726 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3728 void PR_Cmd_Init(void)
3734 void PR_Cmd_Shutdown(void)
3738 void PR_Cmd_Reset(void)
3741 PR_Files_CloseAll();